I'm with AXCS, placing $8.25MM of pref equity (16%: 8% current / 8% accrual) for Abstract Development Group's Ballpark SLC (1345 Jefferson St, Salt Lake City; 122 units plus 3,912 SF of retail; $29.725MM senior loan). We're marketing this on the sponsor's behalf, so the tone should be positive, but every number has to hold up under lender diligence. The package is attached and the draft email is below. Kick off analysis for this offering, inclusive of Sale and Rent comps. Check the manager-quoted expenses (greystar) and give an independent property tax and insurance check. Run a Market analysis including submarket rent growth, occupancy, new supply, demographics, and the current status of Ballpark NEXT and TRAX, with sources.
Abstract Development Group is seeking $8.25MM of pref equity for the development of Ballpark SLC, a 122-unit multifamily development strategically positioned one block from Smith's Ballpark—the future anchor of "Ballpark NEXT," a 14.8-acre entertainment-focused mixed-use development that will transform Downtown Salt Lake City's Ballpark neighborhood into a premier live/work/play destination with direct TRAX access providing seamless connectivity to downtown SLC and the broader metro. (https://cra.slc.gov/ballparknext/).
The project at 1345 Jefferson Street will deliver 122 units (34 studios, 73 one-beds, 15 two-beds) plus 3,912 SF of ground-floor retail, purpose-built for Salt Lake's active urban lifestyle. Amenities include 123 parking spaced, fitness center, dog park & wash, clubhouse, rooftop deck, and outdoor dining areas, while in-unit features—oversized entry closets, urban mudrooms for ski/bike storage, office nooks, floor-to-ceiling windows, and elevated finishes—differentiate the project from commodity multifamily and support premium rents. Renderings: https://buildingsaltlake.com/wp-content/uploads/2023/03/1365-Jefferson-Street-Mixed-Use-sm.pdf
Cash Flow Summary: Untended NCF: $2,658,764 Residential Vacancy Assumption: 6% Commercial Vacancy Assumption: 10% Concessions Assumption: 1 Month Trended NCF: $2,936,968
Loan Summary: Loan Amount: $29,725,000 LTC: 62.42% LTV: 58.70% (Assumes 5.25% Cap & untrended NCF) Untrended DY: 8.94% Pricing: 250 + SOFR
Pref Assumptions: Pref Amount: $8,250,000 Combined LTC: 79.76% Combined LTV: 74.99% (Assumes 5.25% Cap & untrended NCF) Untrended DY: 7.00% Pricing: 16% (8% Current / 8% Accrual)
Sources & Uses:
Summary Sources Item Total $/Unit $/SF % Senior Debt 29,725,000 243,648 341.46 62.3% Mezz/Pref 8,250,000 67,623 94.77 17.3% Equity 9,774,658 80,120 112.29 20.5% Total Sources 47,749,660 391,391 548.52 100.0% Summary Uses Item Total $/Unit $/SF % Land Cost 4,829,864 39,589 55.48 10.1% Pre Development Cost 1,341,881 10,999 15.41 2.8% Hard Cost 33,310,030 273,033 382.65 69.8% Soft Cost 4,548,864 37,286 52.25 9.5% Financing Cost 3,719,022 30,484 42.72 7.8% Total Uses 47,749,661 391,391 548.52 100.0%
Historical Cost Spent To Date ($7,484,720): Land Purchase: $4,829,864 (Current Value Estimate: $5,270,000) Pre-Dev Costs: $1,341,881 Soft Costs: $1,312,975
Developer & Key Principals:
Abstract Development was formed in 2020 as the development affiliate of Bronstein Properties. Bronstein formed the venture in conjunction with Jason Algaze who brings 18+ years of development experience to spearhead the new development focus. Before starting Abstract with Barry & Scott, Jason worked on over $10 billion in new development projects totaling over 8 million square feet and more than 8,000 residential units, including the ultra-luxury 1,400 ft. tower 111 West 57th Street over Central Park; a 45-story, 400-unit; multifamily building in Long Island City called 1 QPS Tower; a boutique condominium building in SoHo called 10 Sullivan; various high-end condominium buildings throughout South Florida, such as ECHO Aventura, ECHO Brickell, Muse Residences & Sage.
Key Principals: Barry Rudofsky & Scott Silverman Combined NW: $98M+ Combined Liquidity: $13.5M+
General Notes:
Project is entitled, and developer expects to be in a position to pull permits next week. Land was purchased in 2022. Originally they utilized a land loan but have since paid that off and hold the land in cash. No affordability or income restrictions
cd scratch/inputs/library; for f in */*.pdf; do echo "#### $f"; python3 -c "
import pdfplumber,sys
with pdfplumber.open(sys.argv[1]) as pdf:
print('pages',len(pdf.pages))
for i,p in enumerate(pdf.pages,start=1):
t=p.extract_text() or ''
print(f'=== PAGE {i} === chars',len(t))
" "$f"; doneSmall enough to read directly.
cd scratch/inputs/library; mkdir -p /vercel/sandbox/extracts; for f in 01a0f375-96db*/*.pdf 01a0f375-96f0*/*.pdf; do python3 -c "
import pdfplumber,sys
with pdfplumber.open(sys.argv[1]) as pdf:
for i,p in enumerate(pdf.pages,start=1):
print(f'=== PAGE {i} ===');print(p.extract_text() or '')
" "$f"; done | tee /vercel/sandbox/extracts/docs_text.txtGoal: select a rent comp set for a proposed new-construction multifamily development so a pref-equity placement package can defend its rent assumptions to lenders.
Subject: "Ballpark SLC", 1345 S Jefferson St, Salt Lake City, UT 84115 (lat 40.740259, lon -111.894936). Market id 41620 (Salt Lake City, UT). The RealAI submarket is "Salt Lake City - Ballpark" (submarket id 0fa2d1b6d4bb11cd1eebdb7dc3defe7f); ZIP 84115 maps to submarket "South Salt Lake" (c928367a3542e07745765436305f7f28); Downtown submarket is 08cefc4e7faa0e10e9a210f692583de4. Program: 122 units — 34 studios, 73 one-beds, 15 two-beds; avg unit ~709 SF (85,283 NRSF); 5 levels wood frame over 2.5-level concrete podium (7 stories), delivery ~2028; Class A finishes, rooftop deck, fitness, dog park, structured parking. Market-rate, no income restrictions.
Method: load the rental-comps skill (sandbox_skills) and follow it exactly. Weight the comp set to the NEWEST deliveries (2015+ and especially 2020+ mid-rise/podium) in the Ballpark, Central Ninth, Granary, South State, Downtown SLC and South Salt Lake areas even at some cost of distance; include any recent lease-ups within ~1.5 miles. Target 8–10 comps. For each comp pull from the RealAI Datamart (property_mfr, topics mf_property_attributes and mf_rent_and_occupancy_snapshot, and mf_rent_and_occupancy_detail if needed for per-bedroom rent/SF) : property_mfr id, name, address, lat/lon, distance to subject (miles), units, year built, stories, asking rent avg and per SF, in-place rent avg, per-bedroom asking rents (studio/1BR/2BR) and per-bedroom asking $/SF where available, occupancy, concessions if any signal, and latest_as_of date. Run explore_data scope=fields before querying fields. Also compute (in a saved python script) the unit-weighted comp-implied average rent for the subject mix (34/73/15) using the median of comp per-bedroom asking rents, both for all comps and for 2020+ vintage comps only.
Output: write subagents/rent_comps/comps.csv (one row per comp, all fields above) and subagents/rent_comps/summary.json (mix-weighted implied rents, per-bed medians, ranges, new-vintage premium observed). Save the script to subagents/rent_comps/rent_comp_calc.py. Return: the comp table, the property_mfr IDs, the per-bed medians and mix-weighted implied rent (all and 2020+), and any gaps/data quality issues (thin samples, null fields, stale dates). Flag conflicts rather than filling them. Do not invent numbers.
Outputs
subagents/rent_comps/comps.csv: 10 comps, all requested fields.subagents/rent_comps/summary.json: implied rents, medians, ranges, vintage premium.subagents/rent_comps/rent_comp_calc.py: reruns end to end. The comp data is embedded in it, copied from the query_data results (property_mfr, mf_property_attributes and mf_rent_and_occupancy_snapshot).Selection method
Comp table (mfr id; distance mi; units; year; stories; ask avg $ and $/SF; in-place avg; ask Studio / 1BR / 2BR; ask $/SF Studio / 1BR / 2BR; occupancy)
| Comp | mfr id | Dist | Units | Yr | Stories | Ask avg / $/SF | In-place avg | Studio / 1BR / 2BR ask | $/SF S / 1 / 2 | Occ |
|---|---|---|---|---|---|---|---|---|---|---|
| The Whitney, 1481 S 400 W (Ballpark) | 95454a45ec32b75c0dcfc7052c90b93f | 0.40 | 264 | 2024 | null | 1,700 / 2.38 | 1,631 | null / 1,387 / 2,027 | null / 2.46 / 2.29 | 66.3% |
| theCHARLI, 828 S Richards | 0af20be4273083bb5ef31cfd3faec4ce | 0.78 | 91 | 2021 | 6 | 1,825 / 2.98 | 1,611 | 1,721 / 1,956 / null | 3.06 / 2.89 / null | 94.5% |
| SevenO2 Main, 702 S Main | 4b17f559347151f7e381a2c447ec9114 | 0.93 | 239 | 2022 | 5 | 1,584 / 2.39 | 1,529 | 1,157 / 1,594 / 2,006 | 2.84 / 2.22 / 2.04 | 90.4% |
| The Hendrey, 340 W 700 S | bb8eb4bfea7be9d2fe0a705b816f2f3b | 1.04 | 348 | 2024 | 6 | 2,059 / 2.86 | 1,702 | 1,512 / 1,837 / 2,636 | 2.75 / 2.91 / 2.76 | 48.3% |
| Journeyman, 646 S 400 W | 4ae01e1b3c120ed5eda7a688d56b4a6c | 1.13 | 184 | 2025 | 7 | 1,727 / 2.86 | 1,678 | 1,488 / 1,790 / 2,824 | 3.05 / 2.58 / 2.73 | 57.1% |
| Bowers Residences, 55 W Utopia (SSL) | 1c60e6187c230a13391ddc57b8bdc7c1 | 1.17 | 236 | 2023 | 10 | 1,623 / 2.14 | 1,544 | 1,111 / 1,583 / 2,207 | 2.40 / 2.17 / 2.00 | 90.3% |
| Post District Residences, 570 S 300 W | 3232c3 (full id 3232c310c0d76fc1b9d80e21843d4288) | 1.22 | 580 | 2023 | 7 | 2,107 / 2.68 | 2,022 | 1,160 / 2,022 / 2,790 | 2.98 / 2.60 / 2.59 | 91.7% |
| 330 Belhaven (SSL) | 672481b9df6c8d8262818f0a63a3f460 | 1.30 | 46 | 2026 | 6 | 1,639 / 3.08 | 1,676 | 1,304 / 1,504 / 2,877 | 3.21 / 3.09 / 2.91 | null |
| Ritz Classic, 2265 S State (SSL) | dafe0c2c584372f734e92e5cafa7839d | 1.36 | 287 | 2018 | 5 | 1,377 / 1.75 | 1,439 | null / 1,296 / 1,654 | null / 1.77 / 1.66 | 95.1% |
| One Burton, 1 W Burton (SSL) | d29669d9af06f0b3e75189e33a1a5994 | 1.47 | 180 | 2023 | 8 | 1,937 / 2.47 | 1,830 | 1,440 / 1,668 / 2,565 | 2.71 / 2.54 / 2.27 | 47.2% |
Per-bed median ask (script output, subagents/rent_comps/rent_comp_calc.py, saved in summary.json)
| Set | Studio | 1BR | 2BR | Mix-weighted avg (34/73/15) | Monthly GPR, 122 units |
|---|---|---|---|---|---|
| All 10 comps | $1,372 (n=8, range 1,111–1,721) | $1,631 (n=10, range 1,296–2,022) | $2,565 (n=9, range 1,654–2,877) | $1,673.68 | $204,189 |
| 2020+ comps (9) | $1,372 (n=8) | $1,668 (n=9, range 1,387–2,022) | $2,600 (n=8, range 2,006–2,877) | $1,700.18 | $207,422 |
New-vintage premium observed (thin; see gaps)
Gaps and flags (not filled)
num_stories null for Whitney. Its building_style is MID_RISE, and the subject's 7-story podium is comparable.Entities referenced: the 10 comps above (all property_mfr). The subject was not queried; coordinates came from the brief.
Goal: select multifamily sales comps to support the exit/stabilized value assumption for a proposed new-construction development used in a pref-equity package. The sponsor values the stabilized asset at a 5.25% cap on untrended NCF of $2,658,764 (~$50.6MM, ~$415K/unit). We need to test that against recent trades.
Subject: "Ballpark SLC", 1345 S Jefferson St, Salt Lake City, UT 84115 (lat 40.740259, lon -111.894936). Market id 41620. RealAI submarket "Salt Lake City - Ballpark" id 0fa2d1b6d4bb11cd1eebdb7dc3defe7f; Downtown 08cefc4e7faa0e10e9a210f692583de4; South Salt Lake c928367a3542e07745765436305f7f28. Program: 122 units (studio/1BR heavy, avg ~709 SF), 7-story podium, Class A, delivery ~2028. Today is 2026-09-30.
Method: load the sales-comps skill (sandbox_skills) and follow it. Prefer 2015+ vintage mid-rise/podium assets, 60–350 units, sold since ~2023, in Salt Lake City / South Salt Lake / urban core. Pull from RealAI Datamart property_mfr (mf_sales_history, mf_property_attributes; run explore_data scope=fields first). For each comp: property_mfr id, name, address, distance (mi), units, year built, stories, sale date, sale price, price/unit, buyer/seller if available. Then supplement with web research (web_search/web_fetch) for 2024–2026 Salt Lake City Class A multifamily trades and reported cap rates (e.g., brokers CBRE/JLL/Newmark/Berkadia, Utah Business, Building Salt Lake, Salt Lake Tribune, Globe St, CoStar news) — capture reported cap rates and price/unit with URL and a short verbatim quote. Also find any published 2025–2026 Salt Lake City multifamily cap rate survey figure (e.g., CBRE Cap Rate Survey H1/H2 2025 or 2026) with URL and quote.
Output: subagents/sales_comps/comps.csv and subagents/sales_comps/summary.json (price/unit range, median, 2020+ median; any cap rates found with source). Return the comp table with IDs and sources, the median $/unit, observed cap-rate evidence with URLs + verbatim spans, and gaps. Flag conflicts; do not invent numbers.
Bottom line: The evidence is thin, with only 2 priced trades since 2023. It doesn't validate the sponsor's ~$415K/unit ($50.6MM/122) at a 5.25% cap. It sits at the top of the range, and the only cap rate found is well below 5.25%.
Datamart coverage is very sparse. I ran four property_mfr queries (market 41620 and county 49035, sales since 2021/2023, year built 2000+/2010+). Only ONE priced multifamily sale came back. The tool has no buyer/seller fields. The queries and their tool result IDs are in the trace (e.g. toolu_bdrk_019bfNMxe1WpCpfUHgMRRDAN).
Comps (the file is subagents/sales_comps/comps.csv; distance is haversine from the subject):
| # | Property (property_mfr id) | Address | Dist (mi) | Units | Built | Stories | Sale date | Price | $/unit | Buyer / Seller | Source |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | Tradition Pointe (07d9c98679032932e94ff9e52ee3d1c4) | 1425 S Jefferson St, 84115 (Ballpark submarket) | 0.09 | 77 | 2024 | 5 (MID_RISE, concrete) | 2025-08-25 | $16,625,000 | $215,909 | n/a | Datamart mf_property_attributes: latest_sale_price 16625000, latest_sale_price_per_unit 215909.09 |
| 2 | Sugarmont (no property_mfr id looked up) | 2191 S McClelland St, Sugar House | 2.14 (from a Traded map coordinate) | 341 | 2021 | not found | closed 2025-05-30 (Centerspace PR); Traded lists 2025-06-18 | $149,000,000 | $436,950 | Centerspace / Cottonwood Communities | https://www.northmarq.com/transactions/sugarmont-apartments-sale-2025-06 ; https://prnewswire.com/news-releases/centerspace-announces-entrance-into-the-salt-lake-city-market-planned-portfolio-transactions-and-quarterly-dividend-302471099.html ; https://traded.co/deals/utah/multifamily/sale/2191-mcclelland-street/ |
| 3 | Hardware Apartments (reference only, 2020, outside window) | 455 W 200 N | n/a (not computed) | 453 | 2018-20 | not found | 2020-05 | $178,000,000 | $392,936 | Oakmont / KBS REIT III | https://altswire.com/kbs-reit-iii-sells-salt-lake-city-multifamily-development-in-off-market-transaction/ ("the sale price of the 464,000-square-foot property was $178 million") |
Trades with no usable price (not in the medians):
$/unit statistics (script: subagents/sales_comps/compute_summary.py):
Cap-rate evidence:
Conflicts and flags:
Gaps:
Goal: gather current (as of 2026-09-30), source-backed facts for a pref-equity offering memo on "Ballpark SLC", a 122-unit + ~3,900 SF retail podium multifamily development at 1345 S Jefferson St, Salt Lake City, UT 84115 (one block from Smith's Ballpark), sponsor Abstract Development Group (affiliate of Bronstein Properties; principal Jason Algaze). Every fact must carry a URL and a short verbatim quote; note publication dates. Flag anything stale, contested, or contradictory. Use web_search and web_fetch.
Research tracks:
Output: write subagents/web_research/findings.md organized by track, every fact with URL, publication date, verbatim quote. Return a compact summary of the load-bearing facts with URLs + quotes, and list gaps/conflicts.
Full findings (URLs, dates, verbatim quotes) are in subagents/web_research/findings.md. Load-bearing points:
Ballpark NEXT
TRAX
Property tax
Insurance
Market and supply
Site and sponsor
Rates
Conflicts to flag: the missing master developer versus the brief's premise; 115 versus 122 units and 2,500 versus 3,900 SF of retail; 13 versus 14.8 acres; the insurance benchmark spread; the Green Line also serving Ballpark; the firm's founding year (2019 versus 2020). The 4–5 source claims on the Salt Lake City rate are secondary.
"""Ballpark SLC (1345 S Jefferson) - pref package diligence checks.
Inputs embedded (sponsor email, FORM estimate p3, Greystar expense comp p1, RealAI comps/benchmarks, SLC Co. tax rate).
Outputs printed; rerun end to end with `python scripts/ballpark_diligence_checks.py`.
"""
import json
U = 122
# ---- Sponsor package (email) ----
senior, pref, equity = 29_725_000, 8_250_000, 9_774_658
tdc = 47_749_660
ncf_untr, ncf_tr = 2_658_764, 2_936_968
cap = 0.0525
land, predev, hard, soft, fin = 4_829_864, 1_341_881, 33_310_030, 4_548_864, 3_719_022
# ---- FORM estimate (p3) ----
gc_all_in = 32_946_729; gc_contingency = 938_154; gsf = 109_499; nrsf = 85_283
# ---- Greystar (p1) ----
gs_opex = 955_598; gs_tax = 183_000; gs_ins = 48_800; gs_mgmt = 96_000
gs_comp_tax_pu = [1491, 1467, 1725, 1856]; gs_comp_ins_pu = [558, 1008, 411, 721]
# ---- Market inputs ----
comp_rent_2020 = 1700.18 # rent comps: mix-weighted 2020+ asking (subagents/rent_comps/summary.json)
comp_rent_inplace = 1615 # 2020+ in-place mix-weighted
other_inc_pct = 0.1382 # SLC MSA mf_pnl_benchmarks other income % of net rent
ins_pct_egi = 0.0236 # SLC MSA insurance % of EGI
vac = 0.06
retail_sf, retail_rent, retail_vac = 3_912, 30.0, 0.10 # retail $30/SF NNN is an assumption
reserves_pu = 250
tax_rate_2025 = 0.009240 # SLC district 13, 2025 (SL County)
tax_rate_2026e = 0.00964 # est. w/ SLC city levy increase (unverified)
res_taxable = 0.55
out = {}
# 1) Capital stack math check
out["LTC_senior_calc"] = senior / tdc
out["LTC_combined_calc"] = (senior + pref) / tdc
out["implied_cost_behind_62.42pct"] = senior / 0.6242
out["value_5.25"] = ncf_untr / cap
out["LTV_senior"] = senior / out["value_5.25"]
out["LTV_combined"] = (senior + pref) / out["value_5.25"]
out["DY_senior"] = ncf_untr / senior
out["DY_combined"] = ncf_untr / (senior + pref)
out["YOC_untrended"] = ncf_untr / tdc
out["YOC_trended"] = ncf_tr / tdc
out["spread_bps_vs_5.25"] = (out["YOC_untrended"] - cap) * 1e4
out["spread_bps_vs_5.53_market"] = (out["YOC_untrended"] - 0.0553) * 1e4
out["sources_sum"] = senior + pref + equity
out["uses_sum"] = land + predev + hard + soft + fin
out["owner_hard_contingency_implied"] = hard - gc_all_in
out["owner_contingency_pct_of_gc"] = (hard - gc_all_in) / gc_all_in
out["total_contingency_pct"] = (hard - gc_all_in + gc_contingency) / gc_all_in
out["soft_pct_hard"] = soft / hard
out["land_pct_tdc"] = land / tdc
out["hard_per_gsf"] = hard / gsf
out["tdc_per_unit"] = tdc / U
# 2) Back-solve rent implied by sponsor NCF (Greystar opex, market other income, retail assumption)
retail_egi = retail_sf * retail_rent * (1 - retail_vac)
def rent_needed(ncf, opex):
egi = ncf + reserves_pu * U + opex
res_egi = egi - retail_egi
net_rent = res_egi / (1 + other_inc_pct)
gpr = net_rent / (1 - vac)
return egi, gpr / U / 12
egi_gs, rent_gs = rent_needed(ncf_untr, gs_opex)
out["implied_EGI_greystar_opex"] = egi_gs
out["implied_rent_pu_mo_greystar_opex"] = rent_gs
out["implied_rent_psf"] = rent_gs / (nrsf / U)
out["premium_vs_comp_2020_asking"] = rent_gs / comp_rent_2020 - 1
out["greystar_fee_3pct_at_implied_EGI"] = 0.03 * egi_gs
out["EGI_implied_by_greystar_fee"] = gs_mgmt / 0.03
# 3) Tax & insurance independent check
vals = {"low_$300k_pu": 300_000 * U, "mid_cost_basis": tdc - land * 0 , "high_$50.6M_value": out["value_5.25"]}
retail_val = retail_sf * 350
tax = {}
for k, v in vals.items():
for rk, r in {"2025": tax_rate_2025, "2026e": tax_rate_2026e}.items():
t = (v - retail_val) * res_taxable * r + retail_val * r
tax[f"{k}_{rk}"] = round(t)
out["tax_scenarios"] = tax
out["tax_greystar_comp_avg_pu"] = sum(gs_comp_tax_pu) / 4
out["ins_greystar_comp_avg_pu"] = sum(gs_comp_ins_pu) / 4
out["ins_msa_benchmark_pu_at_implied_EGI"] = ins_pct_egi * egi_gs / U
tax_uw, ins_uw = 230_000, 700 * U
out["tax_uw"] = tax_uw; out["ins_uw"] = ins_uw
out["opex_adj"] = gs_opex - gs_tax - gs_ins + tax_uw + ins_uw
out["opex_adj_pu"] = out["opex_adj"] / U
# 4) Comp-supported stabilized NCF (today's 2020+ asking, adjusted T&I)
def ncf_at(rent, opex, mgmt_floor=96_000):
gpr = rent * U * 12
net = gpr * (1 - vac)
egi = net * (1 + other_inc_pct) + retail_egi
mgmt = max(0.03 * egi, mgmt_floor)
opex_x = opex - gs_mgmt + mgmt
return egi, egi - opex_x - reserves_pu * U
for lbl, r in {"comp_2020_asking": comp_rent_2020, "comp_inplace": comp_rent_inplace,
"comp_+10pct_premium": comp_rent_2020 * 1.10}.items():
egi, n = ncf_at(r, out["opex_adj"])
out[f"NCF_{lbl}"] = n
out[f"YOC_{lbl}"] = n / tdc
out[f"DY_senior_{lbl}"] = n / senior
out[f"value_at_5.5_{lbl}"] = n / 0.055
_, n_sp_adj = ncf_at(rent_gs, out["opex_adj"])
out["NCF_sponsor_rent_adj_TI"] = n_sp_adj
# 5) Pref coverage & exit
sofr = 0.0388; spread = 0.025
senior_int = senior * (sofr + spread)
pref_cur = pref * 0.08
out["senior_IO_interest"] = senior_int
out["pref_current_pay"] = pref_cur
out["DSCR_senior_sponsorNCF"] = ncf_untr / senior_int
out["coverage_through_pref_sponsorNCF"] = ncf_untr / (senior_int + pref_cur)
n_comp = out["NCF_comp_2020_asking"]
out["DSCR_senior_compNCF"] = n_comp / senior_int
out["coverage_through_pref_compNCF"] = n_comp / (senior_int + pref_cur)
yrs = 3.5 # close ~Q4-26 -> exit ~Q2-30
pref_bal = pref * (1.08) ** yrs # 8% accrual compounding annually on original; current pay separate
out["pref_balance_at_exit_3.5y"] = pref_bal
debt_stack = senior + pref_bal
out["debt_stack_at_exit"] = debt_stack
out["breakeven_exit_cap_sponsorNCF"] = ncf_untr / (debt_stack / 0.98)
out["breakeven_exit_cap_compNCF"] = n_comp / (debt_stack / 0.98)
out["breakeven_NCF_to_repay_pref_at_5.5cap"] = debt_stack / 0.98 * 0.055
print(json.dumps({k: (round(v, 4) if isinstance(v, float) else v) for k, v in out.items()}, indent=1))
json.dump(out, open("extracts/diligence_checks.json", "w"), indent=1, default=str)
mkdir -p extracts && python scripts/ballpark_diligence_checks.py
cd subagents/web_research && grep -n -i -E "partial demolition|mid to late 2026|5-10|10-year|95 feet|vacancy holding|concessions in the|cap rates holding|0092400|45%|caddy|Green|777|115 residences|3.88" findings.md | cut -c1-400
python subagents/rent_comps/rent_comp_calc.py 2>&1 | tail -40
python subagents/rent_comps/rent_comp_calc.py 2>&1 | grep -E "mix_weighted|median" | head
I wouldn't send this email yet. Most of the package holds up: the site, the cost estimate, the loan-to-cost and the sponsor's balance sheet. The problem is the headline cash flow. $2.66MM of untrended NCF needs rents of about $2,260 per unit per month ($3.23/SF) . That is about 33% above the new-construction comps, which average about $1,700 at this unit mix . It's also above the highest-priced comp in the set, 330 Belhaven at $3.08/SF .
At comp rents the deal changes a lot. Stabilized NCF comes in around $1.70MM, yield on cost is about 3.6%, the senior loan covers its interest about 0.90x, and coverage through the pref current pay is 0.66x . A lender will get to this in the first pass, so the sponsor needs to back the rent line before we market it.
| Item | Check | |
|---|---|---|
| Loan-to-cost (senior / combined) | 62.42% / 79.76% | 62.25% / 79.53% on the $47.75MM budget. The email's figure implies a $47.62MM cost |
| Yield on cost (untrended) | not shown | 5.57%, vs. a 5.53% metro cap rate: about 4 bps of spread |
| Owner hard-cost contingency | not shown | The budget's hard cost is $363K over the contractor's $32.95MM number. That's only 1.1% owner contingency on top of 3% contractor contingency |
| Retail SF | 3,912 SF | The contractor estimate shows 2,645 SF of retail . The 2023 design was "115 residences" with "about 2,500-square-feet of retail" . Confirm the approvals cover 122 units |
| "One block from Smith's Ballpark" | framed as an active anchor | The CRA describes it as the "former 14.8-acre Ballpark," and the plan calls for "partial demolition of the stadium" |
The math that does tie: loan-to-value (58.70% senior, 74.99% combined) and debt yields (8.94% senior, 7.00% combined).
Also note the contractor estimate excludes permits, impact and tap fees, offsite work, special inspections, builder's risk and design fees. The remaining soft-cost budget (about $3.2MM after money already spent) has to carry all of those. Lenders will ask for that breakdown.
| Property | Built | Units | Asking | $/SF | Occupancy |
|---|---|---|---|---|---|
| The Whitney (Ballpark, 0.4 mi) | 2024 | 264 | $1,700 | 2.38 | 66% |
| The Hendrey | 2024 | 348 | $2,059 | 2.86 | 48% |
| Journeyman | 2025 | 184 | $1,727 | 2.86 | 57% |
| One Burton | 2023 | 180 | $1,937 | 2.47 | 47% |
| Post District | 2023 | 580 | $2,107 | 2.68 | 92% |
| theCHARLI | 2021 | 91 | $1,825 | 2.98 | 95% |
| 330 Belhaven | 2026 | 46 | $1,639 | 3.08 | n/a |
Four of the recent deliveries are still under 66% occupied, and their asking rents run above what tenants are actually paying. That points to heavy concessions and slow lease-up. The rent case needs to answer for that.
The sponsor's value at a 5.25% cap works out to about $415K per unit. The trade evidence is thin:
A 5.25% cap is defensible only with a lot of explanation. A 5.50% base case is safer.
Greystar's total of $7,833 per unit is reasonable. The two numbers that don't hold are taxes and insurance:
Taken together, taxes and insurance cut NCF by about $85K.
The site is entitled. The contractor estimate is 93% bid-based at $304/GSF. The land is owned free and clear, and the principals have $13.5MM+ of liquidity.
On the sponsor's own NCF, the pref gets its money back at any exit cap up to about 6.4% (pref balance about $10.8MM after 3.5 years) . The sponsor has to back up the rent line to make that cushion stand.
Before I build the development model and redraft the email, I need a few inputs and confirmations. The research files are saved to your library: rent comps (01a0f388-49d1-71e6-8e90-13ff3d95b1b8), sale comps (01a0f388-4b7c-7201-9086-14ca0e364945), web findings (01a0f388-4d45-743d-b1a4-bf2b24b53d52) and the check calculations (01a0f388-4e99-7326-9618-1a9b6da8b6b7).
thanks, I'd like you to underwrite this but the ultimate deliverable is going to be an offering memorandum we can send to prospective lenders (do not build that yet). For size and units go with the larger of each number. Build an Excel model with editable assumptions. Include the capital stack showing where the pref starts and stops, pref accrual through stabilization, refinance and sale take-out, and a downside grid covering exit cap, rents, lease-up and hard costs, showing the cushion below the pref and whether it's repaid in each case. Brand this for AXCS, logo attached.
ls scratch/inputs/agents/*/ 2>/dev/null; f=$(ls scratch/inputs/agents/*/*manifest.md 2>/dev/null|head -1); [ -n "$f" ] && grep -n -i -E "mezz|pref|waterfall|sensitiv|grid" "$f" | head -20; ls extracts subagents/*
Goal: produce the rent-growth and expense-growth assumptions for a development underwriting model (Ballpark SLC, 122-unit podium multifamily at 1345 S Jefferson St, Salt Lake City; construction start Nov 2026, delivery ~Jul 2028, stabilization ~2029-2030). Today is 2026-09-30.
Method (mandatory): load the forecasting skill via sandbox_skills and follow it exactly. It requires running python skills/forecasting/scripts/forecast.py (verify --version first); never compute or estimate a forecast yourself, never port the script. Read references/request.md for payload schema. Build arrays programmatically from query results you save to files (write raw query_data results to subagents/forecast/raw_*.json first, then parse in code); include history_check / peer_history_check.
Run 1 — rent (family rent_or_occupancy): history = RealAI submarket "Salt Lake City - Ballpark" (submarket id 0fa2d1b6d4bb11cd1eebdb7dc3defe7f) mf_rent_ts, period_type MONTH, field asking_rent_latest_avg (note: months before Jul 2024 are null — exclude nulls; valid data Jul 2024–Aug 2026). Peer_history = market id 41620 (Salt Lake City, UT) mf_rent_ts MONTH asking_rent_latest_avg. Check sibling in_place_rent_latest_avg per the skill's sibling rule. Use explore_data before queries. Context signals only from sourced values: SLC MSA supply_snapshot (vacancy 9.5%, under construction 3,682, MF permits T12 4,555 vs prior 2,810 — re-query market 41620 supply_snapshot and permit_ts to source them), migration/demographic_basics for market 41620 if needed; otherwise omit and list in signals_omitted. Horizon: 5 years annual (or the skill's closest). Run 2 — operating expense growth (family operating): follow the skill's guidance for expense growth anchored to its own inflation floor; if it needs a history series and none is available at the market level, report what the skill says to do and do not fabricate.
Output: write subagents/forecast/payload_rent.json, payload_opex.json, result_rent.json, result_opex.json. Return: for each run the base/upside/downside annual growth rates by year (exact engine values), the confidence tier and every data_quality_flags entry verbatim, boom/drawdown guard flags, and the sandbox paths. Flag any problem rather than filling gaps.
Engine: skills/forecasting/scripts/forecast.py --version → params 2026Q3.5 (2026-07-22), sha256 517fce0a1e5d37703c2d6d247a0f09a58db3de38a6f055176037c13b77e37fa9. All numbers below are verbatim engine output. pct_change values are fractions (0.0107 = +1.07%). Nothing was recomputed by hand.
Growth by year (asking rent):
| Case | Y1 | Y2 | Y3 | Y4 | Y5 |
|---|---|---|---|---|---|
| Base | −0.0169 | 0.0 | 0.0 | 0.0 | 0.0 |
| Upside | 0.0107 | 0.0318 | 0.0366 | 0.0421 | 0.0484 |
| Downside | −0.0446 | −0.0318 | −0.0366 | −0.0421 | −0.0484 |
| Case | Y1 | Y2 | Y3 | Y4 | Y5 |
|---|---|---|---|---|---|
| Base | 0.0131 | 0.0037 | −0.0079 | −0.0121 | −0.0121 |
| Upside | 0.0366 | 0.0307 | 0.0231 | 0.0236 | 0.029 |
| Downside | −0.0103 | −0.0233 | −0.0389 | −0.0478 | −0.0531 |
{"status":"error","error":"history has 0 points; minimum is 6"}.operating is 3.5% (~CPI + 100bps; Trepp 2015–2024 MF OpEx CAGR 4.15%, insurance ~11.8%, taxes ~5.4%). It is a house-view parameter in the script's PARAMS block and does not replace a run.All under /vercel/sandbox/subagents/forecast/:
mkdir -p assets && cp "scratch/inputs/library/01a0ee83-3a51-73a2-83e3-fd5da9a0bc0b/AXCS_logo.svg" assets/ && head -c 1500 assets/AXCS_logo.svg; echo; (rsvg-convert -h 120 assets/AXCS_logo.svg -o assets/AXCS_logo.png 2>/dev/null || python3 -c "import cairosvg;cairosvg.svg2png(url='assets/AXCS_logo.svg',write_to='assets/AXCS_logo.png',output_height=120)" || convert -background none -density 300 assets/AXCS_logo.svg -resize x120 assets/AXCS_logo.png); ls -la assets
cat subagents/rent_comps/comps.csv | head -3; echo; cat subagents/sales_comps/comps.csv | head -5; python3 -c "
import json;r=json.load(open('subagents/forecast/result_rent.json'));print(json.dumps({k:r[k] for k in r if k in ('base_case','upside_case','downside_case','confidence','data_quality_flags','horizon','periods')},indent=0)[:1500])"Build an AXCS-branded Excel underwriting model for AXCS's $8.25MM preferred-equity placement in Ballpark SLC. Save it to subagents/model/Ballpark_SLC_AXCS_Pref_Underwriting.xlsx. It will support a lender offering memorandum later, so every number must be traceable and every assumption editable. Today is 2026-09-30.
MANDATORY RULES
xlsx skill (sandbox_skills) first and follow it completely. That covers build rules, input styling, the integrity scan, and recalculation with its recalc.py (LibreOffice). Deliver only after recalc shows zero formula errors.DEAL INPUTS (Assumptions sheet, grouped into sections) Program
Timeline
Revenue
Operating expenses: annual, per the Greystar budget (Jan 2026). Grow at 3.5%/yr from 2027 (input; label it "assumption – no engine output; house structural rate"). Expenses start at TCO at 100%. Show Greystar's original figure beside each overridden line.
Budget (sponsor Sources & Uses)
Capital stack & funding
Takeout (Takeout sheet)
Capital stack sheet ("Capital Stack")
Pref sheet
Monthly CF sheet
Downside sheet: closed-form grids. Each cell is a self-contained formula referencing Assumptions/Takeout.
Market & Comps sheet (hardcoded reference data with source column)
Cover sheet
Notes sheet
After building
Return: the file path, the readback (cells + values), any checks that failed or were approximated, and a list of the input cells (sheet!cell → label) for the main assumptions.
File: subagents/model/Ballpark_SLC_AXCS_Pref_Underwriting.xlsx. Build script: subagents/model/build_model.py. Readback: subagents/model/readback.json. The script builds the workbook, runs the scan and recalc, and writes the readback. Run it from /vercel/sandbox.
Gate status
stray_symbol. Each is the en dash in the mandated title "AXCS | Ballpark SLC – Preferred Equity Underwriting" on B1 of each of the 9 sheets. I kept the title verbatim as instructed. All other HIGH findings were fixed. Advisory items remain (unlocked anchors, minor alignment).Readback (Base case, from the recalculated workbook)
| Item | Cell | Value |
|---|---|---|
| Modeled TDC | Capital Stack!C14 | $49,687,513 |
| Modeled financing need | Capital Stack!C10 | $5,310,344 |
| Financing budget | Capital Stack!B10 | $3,719,022 |
| Financing surplus/(shortfall) | Capital Stack!C15 | ($1,591,322) |
| Funding gap (sponsor shortfall) | Capital Stack!B29 | $1,937,855 |
| Stabilization month | Takeout!B8 | 35 (Sep-2029; date at Assumptions!B28) |
| Takeout month | Takeout!B6 | 38 (Dec-2029; end-of-month date at Takeout!B7) |
| Rent at takeout | Takeout!B15 | $1,671.37/unit/mo (mix rent $1,700.10 × 0.9831 growth index) |
| Stabilized NCF, trended | Takeout!B35 | $1,551,321 |
| Stabilized NCF, untrended | Takeout!C35 | $1,698,867 |
| YOC, untrended NCF / modeled TDC | Takeout!B42 | 3.42% |
| YOC, trended NCF / modeled TDC | Takeout!B41 | 3.12% |
| Value at 5.50% | Takeout!B47 | $28,205,835 |
| Senior balance at takeout | Takeout!B51 | $29,725,000 (shown negative) |
| Pref payoff | Takeout!B52 | $10,619,648 (shown negative) |
| Sale cushion | Takeout!B53 | ($12,702,929), -45.0% of value; repaid? NO (Takeout!B55) |
| Refi loan | Takeout!B72 | $17,722,105, DSCR binding |
| Refi surplus/(shortfall) | Takeout!B77 | ($22,799,764); repaid? NO (Takeout!B78) |
| Additional equity for refi takeout | Takeout!B79 | $22,799,764 |
| Pref XIRR, sale | Takeout!B90 | -51.3% |
| Pref multiple, sale | Takeout!B91 | 0.25x |
| Pref XIRR / multiple, refi | Takeout!B92 / B93 | identical to sale (senior takes everything in both) |
| Break-even exit cap | Takeout!B59 | 3.77% |
| Break-even rent, sale | Takeout!B63 | $2,131/unit (+27.5% vs comp rent at takeout, Takeout!B64) |
| Break-even rent, refi | Takeout!B84 | $2,989/unit (+78.8%) |
| Pref attach/detach, cost, sponsor budget | Capital Stack!D35 / E35 | 62.25% / 79.53% |
| Pref attach/detach, cost, modeled | Capital Stack!D39 / E39 | 59.82% / 76.43% |
| Pref attach/detach, value | Takeout!B56 / B57 | 105.4% / 143.0% |
| Pref accrued at TCO | Pref!E86 | $1,172,534 |
| Pref accrued at stabilization | Pref!E87 | $2,160,055 |
| Pref accrued at takeout | Pref!E88 | $2,369,648 |
| Sponsor-case value | Takeout!B99 | $50,643,124 |
| Sponsor-case senior LTV, recomputed vs stated 58.70% | Takeout!C100 | 58.695% |
| Sponsor-case combined LTV (pref at par), recomputed vs stated 74.99% | Takeout!C101 | 74.986% |
| Sponsor-case cushion | Takeout!C104 | +$9,285,614; YES (Takeout!C105) |
| Model NCF less sponsor NCF | Takeout!B107 | -$1,107,443 (-41.7%) |
| Grid base check | Downside!B43 vs B44, diff B45 | $0 difference, PASS (Downside!B46) |
| Months of lease-up delay the pref can absorb | Downside!B116 | 0 (already NOT repaid) |
Grid dumps (values are in readback.json)
Approximations, conflicts and judgment calls
Main input cells (sheet!cell → label)
Scripts to rerun: subagents/model/build_model.py (builds, gates and writes the readback).
cd /vercel/sandbox && grep -c "–" subagents/model/build_model.py; sed -i 's/Ballpark SLC – Preferred/Ballpark SLC - Preferred/g' subagents/model/build_model.py && python subagents/model/build_model.py > scratch/build.log 2>&1; tail -5 scratch/build.log; F=subagents/model/Ballpark_SLC_AXCS_Pref_Underwriting.xlsx; python skills/xlsx/scripts/workbook_integrity_scan.py $F --json scratch/int.json >/dev/null; echo exit=$?; python skills/xlsx/scripts/recalc.py $F | head -c 400
cd scratch && rm -rf pdf && mkdir pdf && cp ../subagents/model/Ballpark_SLC_AXCS_Pref_Underwriting.xlsx pdf/m.xlsx && cd pdf && timeout 120 soffice --headless --convert-to pdf m.xlsx >/dev/null 2>&1; ls; pdftoppm -r 50 -png -f 1 -l 1 m.pdf cover 2>/dev/null; ls
cd scratch/pdf && timeout 150 python ../../skills/xlsx/scripts/office/soffice.py --headless --convert-to pdf m.xlsx 2>&1 | tail -2; ls; [ -f m.pdf ] && pdftoppm -r 60 -png -f 1 -l 1 m.pdf cover && ls
cd /vercel/sandbox && python3 - <<'E'
from openpyxl import load_workbook
wb=load_workbook('subagents/model/Ballpark_SLC_AXCS_Pref_Underwriting.xlsx',data_only=True)
for c in ["Capital Stack!C14","Capital Stack!C15","Capital Stack!B29","Takeout!B15","Takeout!B35","Takeout!C35","Takeout!B42","Takeout!B47","Takeout!B52","Takeout!B53","Takeout!B55","Takeout!B56","Takeout!B57","Takeout!B59","Takeout!B63","Takeout!B64","Takeout!B72","Takeout!B77","Takeout!B84","Takeout!B90","Takeout!B91","Pref!E87","Takeout!C104","Takeout!B107","Assumptions!B44","Downside!H28","Downside!G28","Downside!F28","Downside!H38","Downside!H41","Downside!A26","Downside!H25","Downside!G25","Downside!B25","Downside!A28","Takeout!B8","Takeout!B6","Assumptions!B28","Takeout!B7"]:
s,a=c.split('!');print(c,repr(wb[s][a].value))
EI've built the workbook and it's attached. At comp rents the pref is not repaid, by a wide margin. We can't write a lender OM on these numbers until the sponsor either backs up rents near the top of the market or changes the capital structure.
Base case (comp rents of $1,700 per unit, 5.50% exit cap, 8 units leased per month):
What gets the pref repaid:
Downside grid at a 5.50% exit cap (cushion below the pref at sale):
| Rent vs. comp | +10% | +20% | +32.9% (sponsor-implied) |
|---|---|---|---|
| Cushion | ($8.0MM) | ($3.4MM) | +$2.4MM |
Rent growth caveat. Rent growth comes from the RealAI forecast engine at low confidence: −1.69% in 2027, then flat . The engine flagged it: "cyclical drawdown suspected: history is short (<= 30mo) and trailing trend is negative. The engine held flat after year 1 rather than extrapolating the correction… Do NOT use this base case as a multi-year assumption without that judgment." The Upside path is on the selector. Even with it, rents in the grid's +10% column still leave the pref unrepaid.
The rent basis is the main thing to argue. The $1,700 base prices each unit type at the comp median rent. The subject's units are larger than most comps (709 SF average), and on a per-SF basis rents would be about $1,900. That is roughly the +10% column above, and the pref still isn't repaid. Operating expense growth of 3.5% a year is my assumption, not an engine output.
Decision for you: the OM can't go out until one of two things happens. Either the sponsor provides a unit-level rent schedule supporting about $3.00/SF, with lease-up comps, or the structure changes: a smaller senior loan, more sponsor equity, or a smaller pref. Otherwise the deal doesn't clear.
Assumptions still unconfirmed (labeled in the workbook; any change moves the results above):
| Metric | Status | Where it goes |
|---|---|---|
| Sponsor rent schedule | Not provided | Assumptions!B36 |
| Loan fee (1.0%) | Unconfirmed | Assumptions!B107 |
| Refinance terms (65% LTV, 1.25x, 5.75% rate, 8% debt yield) | Unconfirmed | Assumptions!B120:B126 |
| Retail rent ($30/SF NNN) | No source | Assumptions!B39 |
| Pref minimum multiple and fee | Not provided | Assumptions!B111:B112 |
Files are in the library:
This offering came to us in March 2026 when the rate environment was more favorable. Make an adjustment to this offering to help it clear. I also have an underwriting model from AXCS, which may have come from the sponsor? See if there is anything in here you can use in order to generate a branded Offering Memorandum.
cd /vercel/sandbox && mkdir -p inputs && cp "scratch/inputs/library/01a0f375-9745-7553-ad7a-0e5310ab3edb/Ballpark GSP Underwriting - Stretch Senior_V11 (Pref).xlsx" inputs/sponsor_model.xlsx && python skills/xlsx/scripts/workbook_profile.py inputs/sponsor_model.xlsx | head -80
Goal: extract everything useful from an existing development underwriting workbook so it can feed (a) a recut of a pref-equity offering to help it clear in today's rate environment and (b) a branded Offering Memorandum for Ballpark SLC (122-unit + retail podium multifamily at 1345 S Jefferson St, Salt Lake City; sponsor Abstract Development Group; AXCS placing $8.25MM pref, 16% = 8% current / 8% accrual, senior $29.725MM at SOFR+250). The file was reportedly prepared around March 2026. Today is 2026-09-30.
File: inputs/sponsor_model.xlsx (in /vercel/sandbox; also library file_id 01a0f375-9745-7553-ad7a-0e5310ab3edb, "Ballpark GSP Underwriting - Stretch Senior_V11 (Pref).xlsx"). 17 sheets incl. Summary, Dashboard, Unit Mix, Proforma, Sources & Uses, Cash Flow, Unlevered Budget, Land Residual Value, and others.
Rules: load the xlsx skill (sandbox_skills) and follow its reading workflow (profile, scan, sample, extract — do not dump every cell). Work on a COPY at subagents/sponsor_model/work.xlsx; run skills/xlsx/scripts/recalc.py on the copy before reading formula values, and report any recalc errors or values that changed materially vs. cached values (read cached values from the original with data_only=True too). Never modify inputs/sponsor_model.xlsx. Every extracted figure must carry its sheet-qualified cell address and value.
Extract, with cell refs:
Output: write subagents/sponsor_model/extract.json (structured, each item {label, sheet_cell, value}) and subagents/sponsor_model/summary.md. Return a compact report of the load-bearing figures with cell refs, the provenance conclusion, the rent per unit/SF by type, and any internal inconsistencies (e.g., figures differing from: LTC 62.42%, combined LTC 79.76%, NCF $2,658,764, TDC $47,749,660, 122 units, 3,912 SF retail). Flag gaps; do not invent.
FILES: subagents/sponsor_model/extract.json (559 items {label, sheet_cell, value} + unit_type_rollup), summary.md (full detail), build_extract.py (rerunnable script producing the JSON), work.xlsx (recalculated copy). Original untouched. Values below are Excel-cached values from inputs/sponsor_model.xlsx.
PROVENANCE
RECALC
HEADLINE FIGURES
DISCREPANCIES vs BRIEF
UNIT MIX (Unit Mix!C10:I32)
| Type | Units | Avg SF | Avg rent/mo | $/SF/mo |
|---|---|---|---|---|
| Studio (S1, S2, J1 and variants) | 34 | 527 | $1,733.83 | 3.29 |
| One-bed (A1–A7 variants) | 73 | 717 | $2,050.66 | 2.86 |
| Two-bed (B1, B1.1, B2A, B3) | 15 | 1,119.5 | $2,910.61 | 2.60 |
| Total | 122 | 713.5 (E32) | $2,068.09 (H32) | 2.8984 (G32) |
PROFORMA (Unit Mix!I38:I66; Proforma!D)
BUDGET (Sources & Uses!D16:D96)
DEBT
TIMELINE (Dashboard!D24:E30)
SENSITIVITY / LAND RESIDUAL / KPIs (hidden sheets)
STALE RATE ASSUMPTIONS (datamart, as of 9/2026)
INTERNAL INCONSISTENCIES / BUGS
GAPS
Scripts: subagents/sponsor_model/build_extract.py (rerunnable).
"""Screening: which pref size / coupon split clears at today's rates. Closed-form, mirrors AXCS model takeout logic.
Inputs: GSP V11 model (Unit Mix sheet) + AXCS T&I + RealAI comp $/SF medians (2020+). Rerun: python scripts/recut_presizing.py"""
import json, itertools
U=122; mix={'S':(34,527,1733.83,2.91),'1':(73,717,2050.66,2.58),'2':(15,1119.5,2910.61,2.44)}
senior=29_725_000; sofr=0.0388; spread=0.025; m=38; sale_cost=0.02; vac=0.06
opex_ex=955_530-96_040-183_000-48_800+230_000+85_400; reserves=30_500
retail=136_920*0.9; parking=169_740
def ncf(rent_basis):
if rent_basis=='sponsor':
gpr=sum(n*r for n,sf,r,p in mix.values())*12
oi=785_761*(1-vac)
else:
gpr=sum(n*sf*p for n,sf,r,p in mix.values())*12
oi=0.1382*gpr*(1-vac)+parking*(1-vac)
egi=gpr*(1-vac)+oi+retail
return egi-opex_ex-max(0.03*egi,96_000)-reserves, gpr/U/12
cases={k:ncf(k) for k in ('sponsor','axcs')}
out={'ncf':{k:round(v[0]) for k,v in cases.items()},'avg_rent':{k:round(v[1],2) for k,v in cases.items()},'rows':[]}
for P,(cur,acc) in itertools.product([8.25e6,7.0e6,6.25e6,5.5e6],[(0.08,0.08),(0.10,0.06),(0.12,0.04)]):
payoff=P*(1+acc/12)**m
r={'pref':P,'current':cur,'accrual':acc,'payoff':round(payoff)}
for k,(n,_) in cases.items():
for cap in (0.055,0.0575,0.06):
r[f'{k}_cush_{cap}']=round(n/cap*(1-sale_cost)-senior-payoff)
r[f'{k}_cov']=round(n/(senior*(sofr+spread)+P*cur),2)
r['extra_sponsor_equity']=8.25e6-P
out['rows'].append(r)
print(json.dumps(out,indent=0))
json.dump(out,open('extracts/recut_presizing.json','w'),indent=1)
cd /vercel/sandbox && python scripts/recut_presizing.py | python3 -c " import json,sys;d=json.load(sys.stdin);print(d['ncf'],d['avg_rent']) for r in d['rows']:print(r['pref']/1e6,r['current'],r['accrual'],r['payoff'],'| spon',r['sponsor_cush_0.055'],r['sponsor_cush_0.0575'],r['sponsor_cush_0.06'],r['sponsor_cov'],'| axcs',r['axcs_cush_0.055'],r['axcs_cush_0.0575'],r['axcs_cush_0.06'],r['axcs_cov'])"
Update the existing AXCS pref underwriting workbook for Ballpark SLC by editing its build script and rebuilding. Do not hand-edit the xlsx: openpyxl save drops the logo images.
Files (in /vercel/sandbox):
MANDATORY
xlsx skill and follow it.CHANGES
After the rebuild:
All 9 changes are built into build_model.py and the workbook is rebuilt; nothing was hand-edited in the xlsx.
Gate: the integrity scan exits 0 (0 high, 253 advisory). Recalc shows 0 errors across 6,511 formulas. The Downside grid base-cell check is PASS (Downside!B46; difference about $0). Logos are on all 10 sheets. Sheet order is Cover, Assumptions, Monthly CF, Pref, Takeout, Capital Stack, Structure Comparison, Downside, Market & Comps, Notes.
Results, default state (Sponsor rent case, Recut structure)
| Item | Cell | Value |
|---|---|---|
| Modeled TDC | Capital Stack!C14 | $48,727,950 |
| Funding gap | Capital Stack!B29 | $976,881 |
| Takeout month | Takeout!B6 | 38 |
| Takeout date | Takeout!B7 | 2029-12-31 |
| Stabilization month | Takeout!B8 | 35 |
| Stabilized NCF, trended | Takeout!B35 | $2,461,633 |
| Stabilized NCF, untrended | Takeout!C35 | $2,622,938 |
| YOC, untrended / trended | Takeout!B44 / B43 | 5.38% / 5.05% |
| Value at 5.50% exit cap | Takeout!B49 | $44,756,959 |
| Pref payoff | Takeout!B54 | -$7,554,233 |
| Sale cushion | Takeout!B55 | $6,582,587 (14.7% of value) |
| Sale result | Takeout!B57 | YES (repaid) |
| Refi loan | Takeout!B74 | $26,851,511 (DSCR test binds) |
| Refi shortfall | Takeout!B79 | -$10,696,237 (pref not repaid by refi) |
| Pref IRR, Takeout sheet | Takeout!B108 | 16.28% |
| Pref multiple, Takeout sheet | Takeout!B109 | 1.5253x |
| Pref IRR, Structure Comparison (contractual, assumes repayment) | Structure Comparison!C32 | 16.28% (As Offered 16.22%, B32) |
| Pref multiple, Structure Comparison | Structure Comparison!C31 | 1.5253x (As Offered 1.5406x, B31) |
| Break-even exit cap | Takeout!B61 | 6.47% |
| Break-even rent, sale | Takeout!B65 | $1,756/unit/mo |
| Break-even rent, refi | Takeout!B86 | $2,775/unit/mo |
The Structure Comparison values above are unaffected by the selectors.
Stress test (scratch copy at scratch/model/stress.xlsx, not the deliverable): AXCS Diligence rent case with As Offered structure. Recalc shows 0 errors, the grid check is PASS, and the Structure Comparison tie check is PASS.
| Item | Value |
|---|---|
| Modeled TDC | $49,305,622 |
| Funding gap | $1,554,553 |
| Stabilized NCF, trended / untrended | $1,987,599 / $2,141,981 |
| YOC, untrended / trended | 4.34% / 4.03% |
| Value | $36,138,158 |
| Pref payoff | $10,619,648 |
| Sale cushion | -$4,929,252 (NOT repaid) |
| Refi loan / shortfall | $21,680,743 / -$18,880,712 |
| Break-even exit cap | 4.83% |
| Break-even rent, sale | $2,020/unit/mo |
| Takeout month | 38 (unchanged) |
Cell map
| Row | Rate | Mar-2026 | Sep-2026 |
|---|---|---|---|
| 166 | SOFR | 3.65% | 3.88% |
| 167 | 10-yr UST | 4.15% | 5.18% |
| 168 | Senior spread | 2.50% | 2.50% |
| 169 | Senior all-in | 6.15% | 6.38% |
| 170 | Perm takeout | 5.66% | 6.18% |
Structure Comparison results (untrended, senior at full commitment)
| As Offered | Recut | |
|---|---|---|
| Pref payoff at month 38 | $10,619,648 | $7,554,233 |
| Additional sponsor equity | $0 | $2,000,000 (14.8% of $13.5MM liquidity; $11.5MM remaining) |
| LTC through pref | 79.53% | 75.34% |
| Sponsor-case coverage through pref | 1.03x | 1.04x |
| AXCS-case coverage through pref | 0.84x | 0.85x |
| Break-even exit cap, Sponsor case | 6.37% | 6.90% |
| Break-even exit cap, AXCS case | 5.20% | 5.63% |
Issues and judgment calls
Scripts: subagents/model/build_model.py is the full build, gate, recalc, readback and stress test. scratch/model/patch1.py, patch2.py and sc_block.py were the edit helpers and are already applied to the build script. The unedited original is at scratch/build_model.orig.py.
cd /vercel/sandbox && python3 - <<'E'
from openpyxl import load_workbook
wb=load_workbook('subagents/model/Ballpark_SLC_AXCS_Pref_Underwriting.xlsx',data_only=True)
ws=wb['Structure Comparison']
for r in list(range(17,33))+list(range(56,80)):
row=[ws.cell(r,c).value for c in range(1,10)]
if any(v is not None for v in row): print(r,row)
EProduce an AXCS-branded Offering Memorandum (Word .docx) marketing a preferred-equity investment in Ballpark SLC to prospective capital providers. Audience: pref/mezz lenders and investors.
Tone: positive and promotional in framing, but every number must survive lender diligence. Present the sponsor's case alongside AXCS's independent diligence case and downside. Never hide a weakness; frame each one with its mitigant. Today is 2026-09-30.
OUTPUT
RULES
docx skill (sandbox_skills) and follow its creation workflow: plain draft with real heading styles, then formatting, text-unchanged verification, visual QA at 200 dpi (read every page image), metadata finalization.convert -background none -density 600 if needed).pdf skill to read the sponsor bio: library file_id 01a0f375-971e-74c8-b91e-4226ce4bdad8 ("Abstract Development - BIO.pdf", 14 pages). Summarize the sponsor team and track record faithfully, with no embellishment beyond it.SECTIONS AND CONTENT (use exactly these figures; the parenthetical sources go in a "Sources & notes" endnote section, not in the body)
| Type | Units | Avg SF | Sponsor rent/mo | $/SF | AXCS diligence rent/mo |
|---|---|---|---|---|---|
| Studio | 34 | 527 | $1,734 | $3.29 | $1,534 |
| 1BR | 73 | 717 | $2,051 | $2.86 | $1,850 |
| 2BR | 15 | 1,120 | $2,911 | $2.60 | $2,732 |
| Total/avg | 122 | 714 | $2,068 | $2.90 | $1,870 |
AXCS diligence rents = 2020+ comp median asking $/SF (Studio 2.91, 1BR 2.58, 2BR 2.44) × unit SF.
The companion Excel model is "AXCS - Ballpark SLC Pref Equity Underwriting.xlsx". Reference it as the supporting model.
Return:
Final docx: subagents/om/Ballpark_SLC_AXCS_Pref_OM.docx. It is 12 pages in the LibreOffice render, and Word may paginate slightly differently. The text-unchanged check passed (439 paragraphs) and the metadata author and company are AXCS.
Other files:
QA caveats:
Figures I computed (script: scripts/build_om.py; all rows in subagents/om/computed_figures.md). The DSCR, coverage, cushion, break-even and March-cushion values match your figures; the script asserts them.
Pref attaches at 62.25% LTC: 29,725,000 / 47,749,661.
Pref detaches at 75.34% LTC: (29,725,000 + 6,250,000) / 47,749,661.
Sponsor equity is 24.66% of cost (shown as 24.7%): 11,776,069 / 47,749,661.
Total sources are $47,751,069 and the difference from uses is $1,408.
Cost per unit is $391,391: 47,749,661 / 122.
Hard cost is $304.20 per GSF: 33,310,030 / 109,499.
The recut cuts the pref payoff by $3,065,415: 10,619,648 − 7,554,233 ($3.07MM).
Value at 5.50% is $47.69MM sponsor and $38.95MM AXCS: NCF / 0.055.
Senior DSCR is 1.383x sponsor and 1.130x AXCS: NCF / (29.725MM × 6.38%).
Coverage through the pref is 1.040x sponsor and 0.850x AXCS: NCF / (29.725MM × 6.38% + 6.25MM × 10%).
Pref detachment LTV at 5.50% is 78.2% sponsor and 95.7% AXCS: (29,725,000 + 7,554,233) / value.
Cushion = NCF / cap × (1 − 2%) − 37,279,233. Values ($MM), all match yours:
| Exit cap | Sponsor | AXCS |
|---|---|---|
| 5.25% | 11.68 | 2.70 |
| 5.50% | 9.46 | 0.89 |
| 5.75% | 7.42 | −0.77 |
| 6.00% | 5.56 | −2.29 |
The March-structure AXCS cushions (−0.36 / −2.18 / −3.84 / −5.36) also tie, using the 10,619,648 payoff.
Break-even exit cap is 6.90% sponsor and 5.63% AXCS: NCF × 0.98 / 37,279,233. That is 140 bps and 13 bps above the 5.50% underwriting cap.
Unit-weighted rent per SF is $2.8985 sponsor (shown as $2.90) and $2.6211 AXCS (shown as $2.62): Σ(units × rent) / Σ(units × SF).
The sponsor rent is 8.2% above the $2.68 2020+ median: 2.90 / 2.68 − 1. The AXCS rent is 9.6% below the sponsor's: 1,870 / 2,068 − 1.
The 2020+ comp median is $2.68 across 9 comps, and matches the brief.
Sales comps: Tradition Pointe is $215,909 per unit (16.625MM / 77) and Sugarmont is $436,950 per unit (149MM / 341).
Implied value per unit at 5.50% is $390,900 sponsor and $319,222 AXCS.
The 2% sale-cost haircut is inferred, not stated in the brief. It is the only haircut that reproduces all your cushion and break-even figures. The OM states it as an assumption. Please confirm it matches the Excel model.
Illustrative refinance proceeds: $28.6MM sponsor and $23.4MM AXCS, versus $37.3MM to repay. I sized these at 1.25x, 6.18%, 30-year amortization (NCF / 1.25 / mortgage constant). This is my addition, not in your brief, and is labeled "illustration" in the text. Delete it if the model's refi sizing differs.
Hard-cost reconciliation: the hard-cost line ($33,310,030) equals the FORM all-in estimate ($32,946,729) less the $284,736 insurance line in soft costs, plus the $648,037 additional contingency. This ties to the dollar, but the "insurance = builder's risk" link is my inference. The $284,736 comes from subagents/sponsor_model/summary.md.
Bio PDF (file_id 01a0f375-971e-74c8-b91e-4226ce4bdad8) conflicts and gaps:
Weaknesses disclosed in the OM beyond your list:
cd /vercel/sandbox && rm -rf scratch/qa2 && mkdir -p scratch/qa2 && cp subagents/om/Ballpark_SLC_AXCS_Pref_OM.docx scratch/qa2/om.docx && cd scratch/qa2 && timeout 150 python ../../skills/xlsx/scripts/office/soffice.py --headless --convert-to pdf om.docx >/dev/null 2>&1; pdfinfo om.pdf | grep Pages; pdftoppm -png -r 70 om.pdf p; ls
cd /vercel/sandbox/scratch/qa2 && montage p-06.png p-07.png p-08.png p-09.png -tile 4x1 -geometry +4+4 m1.png && montage p-10.png p-11.png p-12.png p-01.png -tile 4x1 -geometry +4+4 m2.png && ls -la m1.png m2.png
The deal clears with one change: the sponsor puts in $2.0MM more cash equity, and the pref shrinks to $6.25MM. The pref still earns 16%, but more of it is paid currently (10% paid current and 6% accruing, instead of 8% and 8%). The OM draft and the updated model are attached, both built on that recut.
Rates have moved against the deal since the March 2026 offering:
The pref's claim at the Dec-2029 takeout falls from $10.6MM to $7.55MM . The pref's share of project cost now ends at 75.3% instead of 79.5% . Everything below is at a 5.50% exit cap on untrended cash flow.
| March structure | Recut | |
|---|---|---|
| Sponsor rents: cushion below the pref | $6.4MM | $9.5MM |
| Our diligence rents: cushion below the pref | ($2.2MM), not repaid | +$0.9MM, repaid |
| Exit cap at which the pref is just repaid (our rents) | 5.20% | 5.63% |
| Exit cap at which the pref is just repaid (sponsor rents) | 6.37% | 6.90% |
| Extra sponsor cash | — | $2.0MM, 15% of their $13.5MM liquidity |
It's a George Smith Partners model ("an AXCS company"), last updated March 25, 2026. It supplied what the package was missing:
We kept our own taxes ($230K), insurance ($700 a unit) and the more conservative rent-growth forecast in both rent cases. Our forecast is at low confidence; the forecasting engine flagged a possible downturn. The March model assumed 4% a year.
The March model also has errors a lender will find:
Files are in the library:
The deal clears with one change: the sponsor puts in $2.0MM more cash equity and the pref shrinks to $6.25MM. The pref still earns 16%, but more of it is paid currently: 10% paid current and 6% accruing, instead of 8% and 8%. The OM draft and the updated model are both built on that recut.
Rates have moved against the deal since the March 2026 offering:
The pref's claim at the Dec-2029 takeout falls from $10.6MM to $7.55MM . The pref's share of project cost now ends at 75.3% instead of 79.5% . Everything below is at a 5.50% exit cap on untrended cash flow.
| March structure | Recut | |
|---|---|---|
| Sponsor rents: cushion below the pref | $6.4MM | $9.5MM |
| Our diligence rents: cushion below the pref | ($2.2MM), not repaid | +$0.9MM, repaid |
| Exit cap at which the pref is just repaid (our rents) | 5.20% | 5.63% |
| Exit cap at which the pref is just repaid (sponsor rents) | 6.37% | 6.90% |
| Extra sponsor cash | — | $2.0MM, 15% of their $13.5MM liquidity |
It's a George Smith Partners model ("an AXCS company"), last updated March 25, 2026. It supplied what the package was missing:
In both rent cases we kept our own taxes ($230K) and insurance ($700 a unit). We also kept our lower rent-growth forecast: down 1.7% in 2027, then flat, where the March model assumed 4% a year. The forecasting tool rated that forecast low confidence and flagged a possible downturn.
The March model also has errors a lender will find:
Files are in the library:
Could you generate an OM for Ballpark in this format? Use this branding, these sections, etc. This is AXCS house template
cd /vercel/sandbox && mkdir -p inputs/template && cp "scratch/inputs/library/01a0f3e5-4dec-71e2-b5d0-49908c83f4e4/Haven at Bellaire First Look Memo.docx" inputs/template/haven_template.docx && python3 - <<'E'
from docx import Document
d=Document('inputs/template/haven_template.docx')
s=d.sections[0]
print('page',s.page_width.inches,s.page_height.inches,'margins',s.left_margin.inches,s.top_margin.inches, 'orient',s.orientation, 'sections',len(d.sections))
for i,p in enumerate(d.paragraphs):
if p.text.strip(): print(i,p.style.name,'|',p.text[:110])
print('tables',len(d.tables))
for t in d.tables: print(len(t.rows),'x',len(t.columns),'|',[c.text[:18] for c in t.rows[0].cells][:8])
print('images',len(d.inline_shapes))
Ecd /vercel/sandbox && rm -rf scratch/tpl && mkdir -p scratch/tpl && cp inputs/template/haven_template.docx scratch/tpl/t.docx && cd scratch/tpl && timeout 150 python ../../skills/xlsx/scripts/office/soffice.py --headless --convert-to pdf t.docx >/dev/null 2>&1; pdfinfo t.pdf | grep Pages; pdftoppm -png -r 45 t.pdf p; montage p-*.png -tile 5x -geometry +3+3 sheet.png; ls
Build an Offering Memorandum for Ballpark SLC in the AXCS house template format. The template is the "Haven at Bellaire First Look Memo" .docx. Match its branding, header, watermark, fonts, table styling and section order. Replace all Haven content with Ballpark content. Today is 2026-09-30.
FILES (all in /vercel/sandbox)
pdf skill to read it.MANDATORY
docx skill and follow it. Because a user-supplied template controls the formatting, do NOT run the RealAI default formatter.montage contact sheets (2x2 or 3x2 pages at ~110 dpi) plus a few single pages at 150–200 dpi for dense tables. Check side by side against the template for header, logo, watermark, table style and fonts. Fix overflow, stranded headings and clipped tables.CONTENT, IN TEMPLATE ORDER
Title block: "Ballpark SLC" / "Salt Lake City, UT".
Investment Overview paragraph, template voice: AXCS Investments ("AXCS") is offering a $6,250,000 Preferred Equity investment in Ballpark SLC, a 122-unit, 7-story podium multifamily development with 3,912 SF of ground-floor retail at 1345 S Jefferson Street, one block from the former Smith's Ballpark site. The sponsor is Abstract Development Group, the development affiliate of Bronstein Properties.
"Investment Thesis:" bold lead line, then bulleted theses with sub-bullets:
Project Overview table (2-column, navy label cells like the template). Rows:
Sources / Uses tables, template style with Item, Amount, %, $/Unit.
Sponsor Overview – Abstract Development Group: paragraph plus bullets of projects from the bio, formatted like the template's asset bullets.
Business Plan: construction start Nov-2026, 20 months, TCO Jul-2028; lease-up at 8 units/month managed by Greystar; stabilization Sep-2029 (month 35); takeout by sale (primary) or refinance at Dec-2029. Pref current pay is funded from a pref interest reserve in the budget during construction, "to be confirmed in final budget". No affordability restrictions.
AXCS Financials/Return Summary, mirroring the template's blocks: (a) Scenario table with columns AXCS Diligence case / Sponsor case, and rows for NCF, value at 5.50%, cushion below pref, pref repaid, coverage through pref, senior DSCR. Take everything from Structure Comparison Recut rows (66, 70, 78, 79). (b) Sensitivity table: exit cap 5.25/5.50/5.75/6.00 × both rent cases, showing cushion $ and REPAID/NOT REPAID (Structure Comparison rows 65-72). Add an "As Offered (Mar-26)" comparison row set (rows 57-64). (c) AXCS Preferred Equity Returns block: principal, current pay received through takeout, accrued, payoff, total distributions, IRR, EM (Structure Comparison col C rows 19-32). (d) AXCS Last Dollar Exposure block: at close, LTC through pref 75.34%; at exit, attachment/detachment LTV per rent case (Structure Comparison cols for LTV). (e) Annual cash flow summary (template page 6 style) by calendar year 2026–2029 from the Monthly CF sheet: NOI, senior interest, pref current pay, pref accrued balance, payoff. Inspect the Monthly CF layout to sum by year with formulas-equivalent Python reads; label as "from AXCS underwriting model".
Property Financials: stabilized untrended proforma, Sponsor case vs AXCS Diligence case, with line items GPR, vacancy, other income, retail, EGI, each opex line, NOI, reserves, NCF, expense ratio. Get these from the model where the cells exist (Takeout sheet for the selected case, Structure Comparison rows 35-48 for the NCF build by case). Also note Greystar's original taxes ($183,000) and insurance ($48,800) vs AXCS ($230,000; $700/unit).
Rent Comparables table in template style (Property Name, Distance, Year Built, Units, Occupancy, Asking Rent, Ask $/SF, Studio/1BR/2BR asks) with the subject rows first (Sponsor case and AXCS case), then an Average row. Sales Comparables table: Tradition Pointe, Sugarmont, plus Hardware as a 2020 reference, with Distance, Units, Year Built, Sale Price, Price/Unit, Sale Date, Cap Rate.
Market & Submarket Overview:
Close with a Sources & Notes section and the standard disclaimer (for discussion only, not an offer of securities, projections are estimates, recipients should do their own diligence), then the contact placeholder.
RETURN
I did not build the document. Most of the source files named in the brief are missing from the sandbox, and the brief bars me from inventing figures.
What is in /vercel/sandbox
inputs/template/haven_template.docx (present).scratch/tpl/ with the template renders, t.docx, t.pdf and sheet.png (present).scratch/inputs/library/01a0f3e5-4dec-71e2-b5d0-49908c83f4e4/Haven at Bellaire First Look Memo.docx.scratch/inputs/library/01a0f375-971e-74c8-b91e-4226ce4bdad8/Abstract Development - BIO.pdf. I have not read it yet.What is missing
subagents/ directory, which covers the model workbook (Ballpark_SLC_AXCS_Pref_Underwriting.xlsx and readback.json), the prior OM (docx, charts, computed_figures.md), rent_comps, sales_comps, web_research/findings.md and sponsor_model/summary.md.scripts/, so build_om.py is gone too.extracts/, so the rent-history JSONs are gone.assets/.A full-disk search for Ballpark* found nothing.
What the missing files block
What you need to do
subagents/, scripts/, extracts/ and assets/ directories into /vercel/sandbox (or tell me the correct paths), then rerun the task.scripts/build_om_house.py from a copy of the template, following your brief. It will:
finalize_metadata.py;Files produced: none. No screenshots, page count or QA note, since there is no output document.
cd /vercel/sandbox && ls; ls subagents scripts extracts assets 2>&1 | head -30
cd /vercel/sandbox && L=scratch/inputs/library && mkdir -p staged/charts && cp "$L/01a0f3e4-b988-7028-9831-58fee74d5c8c/"*.xlsx staged/model.xlsx && cp "$L/01a0f3e4-bac7-75b3-bea3-a700cba1a52d/"*.docx staged/prior_om.docx && cp "$L/01a0f3e4-b074-73d6-84da-ec5af2d57c12/"*.csv staged/rent_comps.csv && cp "$L/01a0f3e4-b1d4-715c-83fc-020ff0701ef9/"*.csv staged/sales_comps.csv && cp "$L/01a0f3e4-b3a9-7000-b198-0c510590d85d/"*.md staged/web_findings.md && cp "$L/01a0f3e4-a7bb-741c-be6c-08f2b1e226df/"*.svg staged/AXCS_logo.svg && cp "$L/01a0f3e4-aedc-730a-bd6e-39df672c08c2/"*.xlsx staged/gsp_model.xlsx && cp scratch/inputs/library/01a0f375-971e-74c8-b91e-4226ce4bdad8/*.pdf staged/sponsor_bio.pdf 2>/dev/null; cd staged && mkdir -p om_media && unzip -o -q prior_om.docx 'word/media/*' -d om_media && ls -la . om_media/word/media
Build an Offering Memorandum for Ballpark SLC in the AXCS house template format. The template is the "Haven at Bellaire First Look Memo" .docx. Match its branding, header, watermark, fonts, table styling and section order, and replace all Haven content with Ballpark content. Today is 2026-09-30.
Make the output durable. Keep your script, outputs and any copied data OUTSIDE scratch/.
FILES (all in /vercel/sandbox)
pdf skill and read it.MANDATORY
docx skill and follow it. The user supplied the template, so its formatting takes precedence. Do NOT run the RealAI default formatter.CONTENT (in template order; model cells are the authority for financials)
Title block: "Ballpark SLC" / "Salt Lake City, UT".
Investment Overview paragraph, in the template's voice:
"Investment Thesis:" as a bold lead line, then bullet theses with sub-bullets:
Project Overview table, 2-column like the template:
Sources / Uses tables in template style (Item, Amount, %, $/Unit):
Sponsor Overview – Abstract Development Group: a paragraph plus project bullets in the template's asset-bullet format (Asset Type / Total Units / Year Built or Completed), taken from the bio.
Business Plan:
AXCS Financials/Return Summary, mirroring the template blocks:
Property Financials: stabilized untrended proforma, Sponsor case vs AXCS Diligence case.
Rent Comparables and Sales Comparables tables, template style.
Market & Submarket Overview.
A 3-column table (Metric / Salt Lake City Metro / Ballpark Submarket):
| Metric | Metro | Ballpark |
|---|---|---|
| 12-mo asking rent growth | −0.8% | −9.2% |
| Occupancy | 92.2% | 85.8% |
| Asking rent | $1,736 | $1,585 |
| Asking $/SF | $2.14 | $2.25 |
| MF cap rate (GreenStreet 2Q26) | 5.53% | n/a |
| MF permits T12 | 4,555 | n/a |
| Under construction (C&W) | 3,682 | n/a |
Narrative sections: "Market – Salt Lake City", "Construction & Deliveries", "Submarket – Ballpark" and "Ballpark NEXT & TRAX", drawn from the prior OM text and web_findings.md:
Insert the chart images from the prior OM where they fit, plus the rendering in the property/overview area with the caption "Rendering: Arch Nexus (2023 design submission; design since revised to 122 units)".
Sources & Notes section, then the standard disclaimer (discussion only; not an offer of securities; projections are estimates; recipients should do their own diligence), then the contact placeholder.
RETURN
All other financial figures are read directly from model cells.
cd /vercel/sandbox && python skills/docx/scripts/finalize_metadata.py om_house/Ballpark_SLC_AXCS_OM_House.docx --title "Ballpark SLC - Preferred Equity Offering Memorandum" --subject "AXCS preferred equity offering memorandum for Ballpark SLC, 122-unit podium multifamily development, Salt Lake City" --keywords "Ballpark SLC; preferred equity; multifamily development; Salt Lake City; AXCS" --author "AXCS" --company "AXCS" --description "Prepared by AXCS" --output om_house/OM_House_v2.docx 2>&1 | tail -3; ls om_house; cd om_house/qa && montage contact_1.png contact_2.png contact_3.png contact_4.png -tile 4x1 -geometry 700x+4+4 all.png
cd /vercel/sandbox && convert om_house/qa/all.png -resize 1900x -quality 80 scratch/view.jpg && ls -la scratch/view.jpg
I've rebuilt the Ballpark OM on a copy of the Haven at Bellaire file. It keeps the Haven memo's header, logo bar, watermark, Garamond/navy styling, bullet style and table look. The header now reads "Ballpark SLC / Offering Memorandum". No Haven, Houston or CoStar content is left. It runs 13 pages against Haven's 16, mainly because the financial tables are real Word tables rather than pasted Excel pictures, so you can edit them.
Sections, in Haven order:
What you need to decide or fill in before it goes out:
Layout checks for Word. Garamond isn't installed where I built this, so page breaks may shift slightly when you open it. Also check two things:
Files are in the library:
This is a read-only snapshot of a RealAI analysis.