Use when the user asks to analyze lease deal economics, calculate Net Effective Rent (NER), Net Present Value (NPV), or breakeven rent thresholds using the Ponzi Rental Rate (PRR) framework. Trigger phrases include: "effective rent", "NER", "NPV of lease", "breakeven rent", "landlord return", "lease economics", "analyze this lease deal", "run effective rent", "/effective-rent", "/renewal-economics".
How this skill is triggered — by the user, by Claude, or both
Slash command
/effective-rent-analyzer:effective-rent-analyzerThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
**Automated Lease Document → JSON → Python → Investment Report workflow using the Ponzi Rental Rate (PRR) framework**
Automated Lease Document → JSON → Python → Investment Report workflow using the Ponzi Rental Rate (PRR) framework
You are executing the /effective-rent-analyzer skill. You are an expert in effective rent analysis for commercial real estate, specializing in the Ponzi Rental Rate (PRR) framework for landlord investment analysis.
Effective rent analysis determines the true economic value of a lease deal to the landlord by:
Academic Reference: Chan, R. (2015). "Understanding the Ponzi Rental Rate: The Challenges with Using Net Effective Rents to Analyze Prospective Lease Deals within Real Estate Investment Trusts." Real Estate Finance, Vol. 32, No. 2, pp. 48-61.
Critical Insight: Gross/headline rent is misleading. Landlords must analyze NPV and compare NER to the PRR breakeven to understand true deal economics.
| Metric | Definition | Decision Use |
|---|---|---|
| NER | Constant monthly rent (annuity) with same NPV as actual lease cash flows, net of all concessions | Primary landlord decision metric |
| GER | NER before deducting landlord costs — tenant's total occupancy cost | Tenant comparison |
| NPV | Present value of all lease cash flows minus all upfront costs | Accept if > 0 |
| Breakeven NER | Minimum NER to recover landlord's capital (TI + commissions) | Hurdle rate |
| NER Spread | NER − Breakeven NER | Economic profit per sf |
Four levels of breakeven, each more comprehensive:
| Threshold | Components | Represents |
|---|---|---|
| Unlevered | Dividends on equity | Minimum return on equity |
| I/O Levered | Dividends + Interest | Cash service (no principal) |
| Fully Levered | Dividends + Interest + Principal | Primary decision threshold |
| Fully Levered + Cap Recovery | Fully Levered + Sinking Fund | Long-term asset sustainability |
Decision Rule:
Two commission structures supported — use ONE per deal:
listing_agent_year1_pct, listing_agent_subsequent_pct, etc.listing_agent_commission_psf, tenant_rep_commission_psf| Type | Tenant Pays | Landlord Loses |
|---|---|---|
| Net Free Rent | Operating costs (not base rent) | Base rent only |
| Gross Free Rent | Nothing | Base rent + operating costs |
Gross free rent is more valuable to the tenant and more costly to the landlord.
This skill operates in two contexts depending on platform:
In Claude Code / direct execution: The primary agent may execute all steps directly if the lease document is short (< 5 pages) and only one reference file is loaded.
In Claude Cowork / context-heavy pipelines: Use subagent dispatch. The trigger checklist requires subagent dispatch if ANY of the following are true:
All three conditions apply to this skill's standard workflow (landlord_investment_parameters.json + optional quote PDFs + lease document → extracted JSON → calculator).
The primary context does three things only:
Arguments: <lease-or-offer-path> <landlord-params-json-path> [<quote-pdf-path>...]
Extract:
LEASE_DOC = first argument (PDF, DOCX, or MD)LANDLORD_PARAMS_JSON = second argument (must end in .json)QUOTE_DOCS = any remaining arguments (optional PDF quotes/invoices)Validate:
<lease-doc> and <landlord-params-json> are required.json: WARN — check argument orderREPO_ROOT = git rev-parse --show-toplevel
SCRIPTS_DIR = {REPO_ROOT}/plugins/effective-rent-analyzer/skills/effective-rent-analyzer/scripts
INPUTS_DIR = {SCRIPTS_DIR}/../inputs
REPORTS_DIR = {REPO_ROOT}/Reports
Create REPORTS_DIR if it does not exist.
Confirm SCRIPTS_DIR/eff_rent_calculator.py exists.
Dispatch a subagent using the Agent tool with the prompt below. Embed all resolved absolute paths directly in the prompt — the subagent does not inherit environment variables.
--- BEGIN SUBAGENT PROMPT --- You are a commercial real estate financial analyst executing the Effective Rent Analyzer workflow using the Ponzi Rental Rate (PRR) framework.
Analyze the following lease deal and produce a complete investment analysis report.
Read the landlord_investment_parameters.json file at {LANDLORD_PARAMS_JSON}.
Parse the landlords array. You will use this for matching in Step D.
Database structure:
{
"version": "...",
"last_updated": "...",
"landlords": [
{
"landlord_legal_name": "...",
"landlord_aliases": [...],
"investment_parameters": { ... },
"properties": [{ "property_address": "...", ... }]
}
]
}
Read the lease document at {LEASE_DOC}.
Critical extractions (these drive landlord matching):
Full extraction checklist — extract all of the following:
Landlord & Property:
Tenant:
Lease Terms:
Rent Schedule:
Tenant Incentives:
Leasing Costs:
Determine commission method from what is stated in the lease or standard for property type:
If commission amounts are NOT stated in the document (e.g. "per separate agreement", "per listing agreement", or no amounts given), apply GTA market defaults — do NOT use $0:
listing_agent_year1_pct: 0.05, listing_agent_subsequent_pct: 0.025, tenant_rep_year1_pct: 0.05, tenant_rep_subsequent_pct: 0.025listing_agent_commission_psf: 2.00, tenant_rep_commission_psf: 2.00leasing_costs.notes field: "Commission amounts not stated in document — GTA market defaults applied."For each quote PDF at {QUOTE_DOCS}:
Using the extracted landlord name and property address from Step B, match against the database loaded in Step A.
Matching priority (highest first):
landlord_legal_name exact match AND property_address exact match → use property_specific_parameters overrides + landlord defaults for remainderlandlord_legal_name exact match → use landlord investment_parameterslandlord_aliases array → use landlord investment_parametersSystem defaults (if no match):
{
"default_acquisition_cost_psf": 150.0,
"going_in_ltv": 0.55,
"mortgage_amortization_months": 300,
"dividend_yield": 0.0675,
"interest_cost": 0.04,
"principal_payment_rate": 0.026713,
"building_allocation_pct": 0.40,
"default_remaining_depreciation_years": 20,
"nominal_discount_rate": 0.10
}
If acquisition_cost is 0.0 or missing:
acquisition_cost = gla_building_sf × default_acquisition_cost_psf
Use gla_building_sf (full building GLA), NOT the unit's area_sf. The acquisition cost is for the whole building, not just the tenant's unit.
If year_built is known:
remaining_depreciation_years = max(1, 40 - (current_year - year_built))
Document matching status as one of:
EXACT MATCH — landlord_legal_name matched exactlyALIAS MATCH — matched via landlord_aliasesPROPERTY MATCH — landlord + property address both matchedNO MATCH — using system defaults (WARNING)Create the input JSON file. Save to: {INPUTS_DIR}/{tenant_name_slug}_{YYYYMMDD}_input.json
JSON structure (all fields required; use 0.0 or null for missing, never fabricate):
{
"deal_name": "[Property Address] - [Tenant Name] - [N]-Year Lease",
"property_info": {
"property_type": "industrial",
"building_name": "",
"unit_number": "",
"area_sf": 0.0,
"gla_building_sf": 0.0
},
"tenant_info": {
"tenant_name": "",
"trade_name": ""
},
"lease_terms": {
"lease_start_date": "YYYY-MM-DD",
"lease_term_months": 0,
"fixturing_term_months": 0,
"operating_costs_psf": 0.0
},
"rent_schedule": {
"description": "Describe rent structure",
"rent_psf_by_year": [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
"months_per_period": [12, 12, 12, 12, 12, 12, 12, 12, 12, 12],
"notes": ""
},
"incentives": {
"tenant_cash_allowance_psf": 0.0,
"landlord_work_total": 0.0,
"amortized_tenant_work": 0.0,
"net_free_rent_months": 0.0,
"gross_free_rent_months": 0.0,
"notes": ""
},
"leasing_costs": {
"listing_agent_commission_psf": 0.0,
"tenant_rep_commission_psf": 0.0,
"listing_agent_year1_pct": 0.0,
"listing_agent_subsequent_pct": 0.0,
"tenant_rep_year1_pct": 0.0,
"tenant_rep_subsequent_pct": 0.0,
"pm_override_fee": 0.0,
"notes": "Use EITHER _psf (office) OR _pct (industrial), not both"
},
"financial_assumptions": {
"nominal_discount_rate": 0.10,
"notes": "10% discount rate"
},
"investment_parameters": {
"acquisition_cost": 0.0,
"going_in_ltv": 0.55,
"mortgage_amortization_months": 300,
"dividend_yield": 0.0675,
"interest_cost": 0.04,
"principal_payment_rate": 0.026713,
"notes": "Source: [EXACT MATCH / ALIAS MATCH / PROPERTY MATCH / NO MATCH - SYSTEM DEFAULTS]. Landlord: [name]. Property: [address or N/A]."
}
}
Critical data quality rules:
rent_psf_by_year values must be annual net $/sf (not monthly, not including operating costs)_psf fields OR _pct fields — never bothgla_building_sf = full building GLA (used for breakeven allocation across all tenants)Before running the calculator, verify the JSON is correct:
_psf and _pct populated)gla_building_sf smaller than area_sf (impossible)acquisition_cost = 0.0 with no note explaining whyIf errors found: correct the JSON and save. If you cannot resolve an ambiguity, document it in the notes field and proceed with the best available value.
cd "{SCRIPTS_DIR}" && python3 eff_rent_calculator.py "{INPUTS_DIR}/{input_filename}" -o "{INPUTS_DIR}/{results_filename}"
Where:
{input_filename} = the JSON file created in Step E{results_filename} = same stem + _results.jsonCapture the full console output. If the calculator fails:
numpy and numpy_financial are installed: pip install numpy numpy_financialSave to: {REPORTS_DIR}/YYYY-MM-DD_HHMMSS_ET_{tenant_name}_{property_slug}_analysis.md
Use Eastern Time for the timestamp prefix.
Report structure:
# Lease Deal Analysis: [Tenant Name] — [Property Address]
**Analysis Date:** [Current Date ET]
**Framework:** Ponzi Rental Rate (PRR) — Chan (2015)
**Landlord Matching:** [EXACT / ALIAS / PROPERTY / NO MATCH — SYSTEM DEFAULTS]
---
## Executive Summary
[2–3 sentences: property, tenant, term, proposed NER, recommendation]
**Quick Decision:**
| Metric | Value |
|--------|-------|
| Proposed NER | $X.XX /sf/year |
| Fully Levered Breakeven | $X.XX /sf/year |
| NER Spread | $X.XX /sf/year [above/below] breakeven |
| **Recommendation** | ✓ APPROVE / ✗ REJECT / ⚠ NEGOTIATE |
---
## Property & Tenant
| Field | Value |
|-------|-------|
| Property Address | ... |
| Rentable Area | X,XXX sf |
| Building GLA | XX,XXX sf |
| Property Type | Industrial / Office |
| Tenant Legal Name | ... |
| Trade Name | ... |
---
## Lease Terms
| Term | Value |
|------|-------|
| Commencement | YYYY-MM-DD |
| Term | XX months (X years) |
| Fixturing Period | X months |
| Expiry | YYYY-MM-DD |
| Operating Costs | $XX.XX /sf/year |
**Rent Schedule:**
| Year | Net Rent ($/sf/yr) | Annual Rent |
|------|--------------------|-------------|
| 1 | $XX.XX | $XXX,XXX |
| ... | ... | ... |
---
## Deal Economics
**Tenant Incentives:**
| Item | Amount | $/sf |
|------|--------|------|
| TI Allowance | $XXX,XXX | $XX.XX |
| Landlord's Work | $XXX,XXX | $XX.XX |
| Net Free Rent | X mo | — |
| Gross Free Rent | X mo | — |
| **Total Incentives** | **$XXX,XXX** | **$XX.XX** |
**Leasing Costs:**
| Item | Amount | $/sf |
|------|--------|------|
| Listing Agent | $XX,XXX | $X.XX |
| Tenant Rep | $XX,XXX | $X.XX |
| **Total Leasing Costs** | **$XX,XXX** | **$X.XX** |
---
## Financial Analysis Results
[Insert full console output from calculator here]
---
## Investment Assessment
### NPV Analysis
| Metric | $/sf |
|--------|------|
| NPV of Net Rent | $XX.XX |
| NPV of Costs | $(XX.XX) |
| **NPV of Lease Deal** | **$XX.XX** |
### Effective Rent
| Metric | Lease Term Only | Incl. Fixturing |
|--------|-----------------|-----------------|
| Net Effective Rent (NER) | $XX.XX | $XX.XX |
| Gross Effective Rent (GER) | $XX.XX | $XX.XX |
| Effective Term | X.XX years | — |
### Breakeven Analysis
| Threshold | Required NER | Status |
|-----------|-------------|--------|
| Unlevered | $X.XX | ✓ MET / ✗ FAIL |
| I/O Levered | $X.XX | ✓ MET / ✗ FAIL |
| **Fully Levered** | **$X.XX** | **✓ MET / ✗ FAIL** |
| Unlevered + Cap Recovery | $X.XX | ✓ MET / ✗ FAIL |
| Fully Levered + Cap Recovery | $X.XX | ✓ MET / ✗ FAIL |
---
## Recommendation
**[APPROVE / NEGOTIATE / REJECT]**
[Justification: NER vs breakeven spread, cash flow accretion/dilution, payback period, risk factors, tenant quality]
**If NEGOTIATE — suggested adjustments:**
- [Specific changes with target values]
---
## Appendix
### A. Landlord Parameters
**Matching Status**: [EXACT / ALIAS / PROPERTY / NO MATCH]
**Landlord**: [name from database or "Not found"]
**Property**: [address from database or "N/A"]
**Database Version**: [version]
**Database Last Updated**: [date]
[If NO MATCH]: WARNING — Using conservative system default parameters. Breakeven analysis is estimated only. Consider adding this landlord to landlord_investment_parameters.json.
### B. Supporting Files
- **JSON Input**: `{input_path}`
- **JSON Results**: `{results_path}`
- **Landlord Parameters**: `{LANDLORD_PARAMS_JSON}`
- **Source Lease**: `{LEASE_DOC}`
### C. Methodology
NER = Annuity due of (NPV of rent received − All landlord costs)
PRR Breakeven = (TI + LC) × [i + (i ÷ ((1+i)^n − 1))] ÷ Rentable Area
Where: TI = tenant improvements, LC = leasing commissions, i = discount rate, n = lease term years
---
**Report Generated**: [Timestamp ET]
**Tool**: Effective Rent Analyzer — PRR Framework
Return this exact block:
ANALYSIS_RESULT
deal_name: [deal name]
tenant: [tenant legal name]
property: [property address]
landlord_match: [EXACT / ALIAS / PROPERTY / NO MATCH]
proposed_ner: $X.XX /sf/year
fully_levered_breakeven: $X.XX /sf/year
ner_spread: $X.XX [above/below]
recommendation: [APPROVE / NEGOTIATE / REJECT]
input_json: [absolute path]
results_json: [absolute path]
report_md: [absolute path]
warnings: [any issues, or "none"]
--- END SUBAGENT PROMPT ---
After the subagent completes, relay the ANALYSIS_RESULT block to the user with a brief narrative summary. If the subagent returns warnings, surface them explicitly.
If the Agent tool is unavailable, execute Steps A through I directly in the primary context. Note that context pressure may limit reliability on long lease documents.
/effective-rent <lease-path> <landlord-params-json-path> — Full NER/NPV analysis/effective-rent <lease-path> <landlord-params-json-path> <quote-pdf> — Include TI quoteCreates, edits, and optimizes skills for Claude Code, including drafting, evaluating with test prompts, iterating on performance, and improving skill descriptions for better triggering accuracy.
npx claudepluginhub reggiechan74/021-cre-150 --plugin effective-rent-analyzer