RealtyPad — triage¶
Hard rules¶
- Prefer evidence over Economics alone — Economics with estimated tax or capped rent lie.
- Scores: prefer
score_summary. Economics / Data confidence / Growth / Overall — seeread_doc("agents/glossary.md"). Never call Overall “score.”min_scorefilters Economics only. - Read
score_summaryanddata_gapsonlist_deals/get_deal(core) first. data_gaps: list of{ code, blocking, detail }. Anyblocking: truegap means do not advance research → score/UW / claim ready. Soft gaps (tax_estimated,missing_growth_drivers, etc.) can proceed with eyes open. Codes:photos,rent,adr,arv,unscored(investment / either only),housing_cost_missing(primary only — no ask/purchase or nopiti_v1housing cost; primary deals keepscorenull by design),tax_implausible(blocking: statedtax_annualunder $100/yr or under 0.1% of purchase — a placeholder like $1; scoring uses the workspace tax estimate until a real tax bill is entered),tax_estimated,insurance_estimated,vacancy_estimated,hoa_estimated(insurance/vacancy/HOA still equal to an automation market-trend fill — cleared when a verified value replaces it),rent_capped,repairs_unknown,missing_growth_drivers. Strategy money gaps (rent/adr/arv) coverstrategy_intentwhen set (union), else the singleincome_strategy.- Early pass (trash): when Economics is already weak (≲ ~40 / fails the strategy economic bar on known inputs) and Overall is negative or Growth is clearly negative (≲ −30) with no distress/buyer override — set
passedwithout a full research deep-dive. Still skim listing + comments; do not invent numbers to “save” it. - Prioritize research on deals with blocking
data_gaps, decent Economics but low Data confidence (confidence_gaps/ soft gaps), or missing Growth income series (growth_gaps). Preferhas_blocking_gap=true/has_gap=<code>. Soft gaps queue:has_soft_gap=true(deprecatedneeds_inputstill aliases). - Fill data gaps with
get_agent_manual(workflow=research)before judging keepers. - For regional/cluster passes, refresh stale markets once via
get_agent_manual(workflow=trends)(dedupe deals;ensure_geo_markets+refresh_deal_trends(gap_fill=true)per deal when needed — not agent CSV → upsert; surgical refresh only when needed). - For verdict + status on individual deals, follow
get_agent_manual(workflow=underwrite)(which callsget_agent_manual(workflow=scenarios)). - For scenario-only / sensitivity / bid variations without a full verdict, follow
get_agent_manual(workflow=scenarios). - Never invent numbers. Pattern-pass only when the failure mode is already documented.
- Read comments + open
action_neededhandoffs before flipping a deal that was previously researched.
Aggressiveness¶
Defaults by income_strategy (see AGENTS.md / get_agent_manual(workflow=underwrite)). Chat override: aggressiveness: aggressive|moderate|strict (or “be aggressive” / “be conservative”). strict (“be conservative”): LTR/STR fallback CF ≳ ~$200/mo (≈ Economics ~70) or a clearly stronger hold than moderate; flip ≳ $50k; wholesale ≳ $40k.
| Strategy | Mode | Clears economic bar |
|---|---|---|
ltr / str |
moderate | Prefer hold projection (cashflow_projections via underwrite) over month-0 CF; fallback CF ≳ ~$100/mo only if projection unavailable |
fix_flip / wholesale |
aggressive | Clear asymmetric profit/spread only (flip ≳ ~$40–50k / Economics ~80; wholesale ≳ ~$25–40k / Economics ~70) |
Pursue vs pass: economic bar is necessary but not sufficient. After a deal clears economics (and is not a structural pattern-pass), underwrite runs match_deal_buyers (live UW + selected scenario snapshots): matches → ranked; buyers scanned but none fit → passed; empty buyer book (scanned=0) → watch (Hold — no buyers yet; research done — keep an eye out). Hard external gaps → blocked. Human escalate ranked → pursuing. Full tree: get_agent_manual(workflow=underwrite) Status decision tree.
Queue modes¶
Match UI /triage stage tabs (labels: New, Blocking gaps, Soft gaps, …):
new (default inbox)¶
list_deals(status="new", limit=80)
Ingested, not started. Start research → researching, or pass / block.
Blocking gaps (UI mode id needs_research)¶
Any blocking data_gaps entry (photos / rent / ADR / ARV / unscored / housing cost):
list_deals(status="new,researching", has_blocking_gap=true, limit=80)
list_deals(has_gap="photos", limit=80)
Use has_blocking_gap=true (same predicate as Blocking gaps).
Soft gaps (UI mode id needs_verification)¶
Estimated tax/insurance, rent capped, repairs_unknown, listing off-market/auction, or missing listing contact/description:
list_deals(has_gap="tax_estimated", limit=80)
list_deals(has_soft_gap=true, limit=80)
has_soft_gap is the soft-gap OR convenience for this queue; prefer per-code has_gap when targeting one soft flag. Deprecated needs_input aliases has_soft_gap when unset.
blocked / watch / ranked / pursuing¶
list_deals(status="blocked", limit=80)
list_deals(status="watch", limit=80)
list_deals(status="ranked", limit=80)
list_deals(status="pursuing", limit=80)
blocked: hard external stop — unblock when the fact clears.watch(UI: Hold — no buyers yet): economics already clear; empty buyer book or parked — not more research; resume when buyers appear. New/reopened/changed buyers auto-flag fitting Hold deals with anaction_neededhandoff (raw.tag=watch_resurface) — work those first:match_deal_buyers→ranked(seeget_agent_manual(workflow=buyers)).ranked/pursuing: pursue pipeline.
Hide low data-confidence watch unless the user asks to show them (UI default).
regional / cluster¶
Filter by q, market_id, or shared builder/HOA/subdivision after loading a stage slice. Process the cluster as one thesis, not 50 isolated vibes.
Batch workflow¶
Triage Progress:
- [ ] 1. Pick mode + scope (N deals or geography/builder)
- [ ] 2. Load queue via list_deals; sample before full pass; read data_gaps on each item
- [ ] 3. Regional/cluster: dedupe market_ids → get_agent_manual(workflow=trends) for stale (~35d) or below the 120-month target (unless source is known shorter) home + LTR rent (STR if str deals; request up to 10y)
- [ ] 4. Detect pattern (see below) vs needs research / full UW
- [ ] 5a. Pattern-pass: `update_deal_status` (single) or `update_deals` **status+rationale only** (cluster — no money in the same call)
- [ ] 5b. Keepers with blocking data_gaps → get_agent_manual(workflow=research), then UW when clear
- [ ] 5c. Otherwise get_agent_manual(workflow=underwrite) (scenarios + buyer match)
- [ ] 6. Brief with canvas: counts, verdicts, remaining queue
Pattern-pass¶
When a whole cluster fails for the same documented reason (HOA tax bomb, builder premium, flood zone, etc.), batch passed with a shared short Status note (rationale) via status-only update_deals — do not invent per-deal numbers and do not mix money fields in that call. Single deal → update_deal_status.
MCP¶
| Action | Tool |
|---|---|
| Queue | list_deals (has_blocking_gap, has_gap, Soft gaps via has_soft_gap, min_score, status, q, market_id; read score_summary + data_gaps; archived excluded by default) |
| Detail | get_deal core (score_summary + data_gaps + counts); view=overview/full or list_* for nests |
| Status / Status note | update_deal_status (single); update_deals status+rationale only for cluster pattern-pass |
| Money / archive | update_deal / update_deals (money-only; archived=true/false) — never mix with status |
| Buyer fit (via UW) | match_deal_buyers (snapshots on by default; returns scenario_run_id) |
| Comment | add_comment |
Brief format¶
Use a Cursor canvas for batch results:
| Address | Prior → verdict | Corrected CF | Buyers | Notes |
|---|---|---|---|---|
| … | new → passed | −$120/mo | — | tax $X |
| … | researching → ranked | +$180/mo | 2 matches | linked Diego |
Also give: how many cleared, how many left in queue, suggested next cluster.