A working system, built end to end
with Claude Code and Codex, end to end
Sobin George Thomas, with the ArkOne team.
Twenty stages, in the order you run them by hand today. Each chapter opens with how the stage is done by hand, gives one number, shows the build with one tool (chapters alternate Claude Code and Codex, so a reader on either finishes the system), names what the stage feeds, and says what stays with a person. The two appendices collect every build step by tool. Every number carries its source or says it is modelled. No chapter claims a demo that is not public.
Chapter 1
Tool: Claude Code · Memory MCP · Filesystem MCP.
Pick an asset type and hope. Offices, say, in one submarket. A trigger if you can name one. Then the portal filter. For a six-person brokerage the answer to who actually calls sits in a year of proposals, unread.
Nothing does this stage for you. Every tool in the category starts one step later, at a filter form you have already filled. The trade has written almost nothing down about how it chooses, so this chapter is short.
What it has written is the vocabulary, in vendor copy: define "property type, size range, submarket, and the primary trigger signal you're targeting (lease expiration, loan maturity, long tenure, etc.)" Prospect by Buildout, https://www.prospect-by-buildout.com/blog/building-owners-list-finding-commercial-property-owners-in-your-market
Take only the sequence. Four filters, then a category. Owners.
What the category hides is who is behind the asset.
"Many properties owned by LLCs are actually small-time investors, individuals, and families." tresil, Hacker News, https://news.ycombinator.com/item?id=29087150
He goes on: "whether individuals who own 1-5 properties, or huge institutional investors who own thousands." A family with three flats and a fund with a thousand wear the same legal clothes on the title. The category does not say which one calls you. Your own past work does.
Zero published hours Nobody has measured what this stage costs, and this chapter will not guess. The traceable cost lands four chapters on, when a wrong definition sends you to a credit bureau.
Source: none found in the instructional material the trade publishes, checked 14 September 2026
A definition that lands on anonymous holding companies pushes the whole chain into bought ownership data; chapter five shows that lane. One that lands on named owners never goes there.
Open Claude Code. Ask who called. It reads a year of proposals off disk, one row per job: who called, what asset, what for. It groups the rows and writes one sentence per group, with the count behind it. You keep one, and the list is built from it.
Open Claude Code in a new folder. Point the Filesystem MCP at your proposals and closing files, add the Memory MCP so what it learns survives the session, and say what you want:
Read every proposal and closing file from the last twelve months. Write
one row per file: the date, who called and what kind of entity, the
asset, the submarket, the trigger if the file shows one (never guess;
write unknown), what I was asked to do, whether it closed. Group the
rows by what I was asked to do and by who called, and write one
sentence per group: the entity, the asset, the submarket, the problem
that made them call. Save work.csv and target.md, keep each group in
memory, and report the row count behind every sentence.
Back come a few sentences, a count under each. Fourteen rows behind a sentence is
a problem people call you for; one row is a job you once took. Keep one, two at most, at the
top of target.md.
Two honest limits. The Filesystem MCP reads only the folders you allow it, so work that lives in an inbox or a WhatsApp thread never becomes a row. And the sentence is a first draft: who is behind an asset is invisible until the list exists, so chapter three sends rows back here. Define, then let the list correct you.
The list. The next stage lists every owner in your patch from the public record, filtered on your sentence. The number to read: rows that survive the next gate, against rows in total.
The public record has no column called problem, so the next stage filters on your sentence.
The number that proves this stage worked arrives two chapters on, at the qualification gate. Lose nine rows in ten there and the sentence was a category wearing a longer coat; it comes back here.
Which clients you want. The tool counts who called. It cannot say which you would take again, or turn down. You rule once, in the file the tool reads, and the next run applies it.
The tool can tell you that eleven of last year's calls were families selling a second flat and
three were funds. It cannot say which you want more of. None of this is a data problem. You
choose, write it under the sentence in target.md, and the list stage reads both.
Nothing new to buy. CRM: the closed deals, who called and why. Folders: the proposals, the raw material of the sentence. Portal: asset and price filters, nothing about the problem behind a listing.
CRM holds the closed deals, if you logged them. Folders hold the proposals it never saw. Portal filters run on asset and price, never on why an owner might sell.
One sentence naming who calls you and why, with the past work counted behind it. Then the list can be built.
Ask: If you wrote down the one problem people call you for, how many files from last year would fit it?
The book runs all twenty stages in order; the address here is chapter 1.
Chapter 2
Tool: Codex · Chrome DevTools MCP · Firecrawl MCP · Google Sheets MCP.
One address at a time, then a company. The register gives the recorded owner by address or parcel. The name it hands back is often a company. For a six-person brokerage the list is a spreadsheet built one search at a time, between viewings.
Public registries and planning portals already publish most of this, for free. The work is the join. Whatever your market calls them, three public sources carry the list: a land registry, which says who holds the title to a building; a planning portal, which says who applied to change it and when; and a company register, which says what sits behind a company name.
By hand, that means taking target.md from the last chapter, opening the registry, searching
one address, copying the recorded owner into a spreadsheet, and going again. Often the name is
a company, and a company on a title is thinner than it looks:
"Many properties owned by LLCs are actually small-time investors, individuals, and families. LLCs only became a popular/viable way to own real estate in the last couple decades." tresil, Hacker News, https://news.ycombinator.com/item?id=29087150
One search per asset Plus one puzzle per company name, because the register hands back an entity and not a person. Four hundred assets is four hundred searches before the sorting can begin.
Source: modelled
No published figure says how long this stage takes, and this book will not invent one. What can be said is the shape of the cost: one search per asset, and a second problem for every company name. The products that sell the join print no price. CoStar (https://www.costar.com/products/property-records) and Reonomy (https://www.reonomy.com/resources/property-search/) both sell by quote. The data underneath them is free.
Open Codex. Ask for the join. Every row names its source: the land registry, the planning portal, the company register, with the page and the date. A company name is written as a company, never as an owner. Nothing reaches the sheet without its source.
Open Codex in the engine folder, where target.md from the last chapter sits: one page naming
the streets, the asset type, the trigger. Connect three servers. Chrome
DevTools MCP drives your own Chrome and lists every request a page makes, so where a portal
fetches its results as a data file and then draws it, Codex reads the file instead of scraping
the drawing. Firecrawl MCP crawls a planning portal whole, without you pressing next. Google
Sheets MCP is where the list lands; budget fifteen minutes for the Google sign-in it needs.
Then say what you want:
Read target.md. For every asset in it, build one row from the public
record and write where each fact came from: the land registry for who
holds the title and since when, the planning portal for who applied to
change the building and when, the company register for what sits behind
a company name. Open each portal in Chrome; where the page loads its
results as data, read the data, not the drawn page.
Where a portal is plain pages, crawl it with Firecrawl. Write the owner
exactly as the register spells it, and mark each row person or company.
Never guess a person behind a company. Put the page and the date on every
row. Write the rows to a Google Sheet called Owners, and report three
counts: rows built, rows where the owner is a person, rows where it is a
company.
What comes back is a script, a run over the patch and a report with three counts. The sheet called Owners holds one row per asset: the owner as the register spells it, person or company, the page and the date. The company rows stay; the human behind each is chapter 4, starting from the page.
Three honest limits, which Codex will tell you about. The recorded owner is often a company, and this build does not try to see through it; a row marked company is a true row. Every register is its own site with its own search, so a reader built for one stops at its border; the public county scrapers each cover one county, the most-starred last pushed in December 2022 (https://github.com/codefornola/assessor-scraper). And the one live build nearby, PropertyWebScraper (https://github.com/RealEstateWebTools/property_web_scraper, pushed July 2026), reads listings; a search of its source found no file that knows the word landlord. It can tell you what is on the market, and nothing about who owns the street.
The browser server reads whatever your Chrome is signed into, by design (https://github.com/ChromeDevTools/chrome-devtools-mcp). Run it in a Chrome with only the portals open.
Sorting them. The next stage keeps the twenty worth a call and writes down why. It reads the sheet, never a portal. The number to read: rows built, beside rows where the owner is already a named person.
The next stage reads the Owners sheet row by row, pulls the recorded documents for each parcel and scores the row with a reason. Without the page and the date, it has nothing to read.
The number that proves this stage worked is two, side by side: rows built, and rows where the owner is a named person. Four hundred assets with ninety people is a different week from four hundred with three hundred and eighty.
Which streets, which trigger. The tool sweeps whatever patch it is given. It cannot decide which submarket is yours or which signal matters this quarter. A person rules once, in the target file, and the next sweep reads it without asking.
The sweep needs no person. The target does. What sits behind an asset is invisible until the list is built, so this stage is the first test of the chapter 1 definition. A patch that returns nine company names in ten is telling you something, and a person decides whether to narrow the streets or accept the extra work.
A name that reads like a person trading as a business is a ruling too. Rule once, in
target.md.
Nothing new to buy. Sheet: the list, one row per asset, its page and its date on every row. Browser: the registry and the portal, opened by the tool instead of by you. CRM: stays empty until the sort. A raw list is not a pipeline.
Sheet gains one row per asset, with its page and its date. Browser is driven by the tool, which opens the registry page you would have opened. CRM stays out on purpose. Four hundred unsorted rows in a pipeline is how a CRM becomes a graveyard; the sort earns a row its place.
Every owner in the patch on one sheet, the page beside each, every company marked as one. Then the sorting can be automatic.
Ask: How many of the owners on your list today came from a page you could open again tomorrow?
The book runs all twenty stages in order; the address here is chapter 2.
Chapter 3
Tool: Claude Code · Google Sheets MCP · Airtable MCP.
Rank on a trigger, then forget why. Four hundred rows from the last chapter. A Sunday pass by eye: this one, not that one, maybe. For a six-person brokerage the kept rows and the dropped rows sit in one sheet, and nobody wrote down why.
The nearest built thing is a county assessor scraper, and it does this stage for one county. Three sit on GitHub: New Orleans (last pushed December 2022), Oklahoma, Cook County. Each parses one county's website and stops. None scores a row or writes a reason beside it. Unless your patch is one of those counties, nothing public does even the half that exists.
So the stage runs by hand, and the question is the Sunday one: which of these four hundred is actually going to transact, and how do I know? The trade's own instruction names what to look for, and every item is an event, never a description of the building:
"lease expiration, loan maturity, long tenure" Buildout, https://www.prospect-by-buildout.com/blog/building-owners-list-finding-commercial-property-owners-in-your-market
Two of those sit in the public record. The deed carries the date the asset last changed hands, which is the tenure. A recorded mortgage carries its maturity. The lease is usually not recorded, and that one missing signal is what CoStar and Reonomy sell; neither prints a price.
You open the deed, form a view and tick the row or delete it. A deleted row leaves with its reason. A ticked row carries none, so next time it is judged again from nothing.
400 lookups One recorded-document search per asset on the list, by hand, before a single row can be ranked. Then the same lookups next quarter, because nobody wrote the verdict down.
Source: modelled
Nobody has published how long this stage takes; this chapter will not invent an hour. The unit is one lookup per asset on the last chapter's list. The rework is the second cost: a row deleted for a good reason comes back at the next sweep, because nothing remembers why it left.
Open Claude Code. Ask for the reason. The tool that reads the row writes its score and its reason beside the row, dated, in two columns. A row nobody scored stays blank, never zero. A row archived stays archived, with its reason.
Open Claude Code in the engine folder. The owner list from the last chapter sits in a Google Sheet or an Airtable base. Connect it: for Sheets, the community server taylorwilsdon/google_workspace_mcp, with fifteen minutes budgeted for the Google Cloud OAuth setup; for Airtable, Airtable's own hosted server or the community domdomegg/airtable-mcp-server. Then say what you want:
Read the owners sheet, every row, and tell me the total before you start.
Skip any row whose status column reads archived; leave it and its reason
untouched. For each other row, read the recorded documents for the
parcel: the deed for the date it changed hands and the mortgage for its
maturity. Add columns beside the row: tenure in years, months to
maturity, the date you read them, and a one-line reason saying which
signal is live and where you read it. Score the row against
weights.md in its own column. Where you found no documents, leave the
score blank and write the reason as not read; never write zero. Report
three counts: rows read, rows with a live signal, rows you could not read.
What comes back is a script and three counts. Sort by score and the top twenty are the call list; the reason column is the opening line of each call.
Two rules are the whole stage. The score and the reason are written beside the row by the tool that read it, so a company archived last quarter stays archived, with its reason, through every later run. And a row nobody scored stays blank, because a zero on that row would read as a judgement, and nobody made one.
Two honest limits, which Claude Code will tell you about. The lease is rarely on record, so the signal the trade prizes most is written as not on record, a blank and never a no. The community Airtable server returns a hundred rows per call unless asked for more, which is why the instruction asks for the total first: four hundred rows read as a hundred is a list that lies quietly.
Finding the human. The next stage takes only the rows with a live signal and finds the person behind the entity on the deed. The number to read: first contacts that land on an owner with a live event, against calling on fit alone.
The next chapter finds the human behind the holding company. That is slow work, so it gets twenty rows, and it needs the reason each row is there, because the first message, three chapters on, opens with it.
The number that proves this stage worked is the share of first contacts that landed on an owner with a live event: a maturity inside twelve months, or a long tenure for your patch. Count it against calling on fit alone.
The weight, and the one you know. How much a maturity counts against a long tenure is yours, written once where the next run reads it. A low score on a row you know something about is overruled by you, in the reason column, in your words.
The tool reads the record. It does not know the owner of the corner block told you over dinner that he sells next spring. The score is for the strangers, owners you have never met with an event coming. The people you already know need no column.
Two rulings stay with a person. The weight on each signal is written once, in weights.md,
where the next run reads it. Whether to pursue a row the record scored low is written in the
reason column, and a later run leaves it alone.
And there is no threshold. The tool never drops a row on its own; twenty is a number you choose.
Nothing new to buy. Sheet: the score and the reason beside every row, written by the tool that read the row. Register: the recorder or land registry you already search by hand, read by the tool instead. CRM: gets the twenty, each carrying its reason.
Sheet is the Google Sheet or Airtable base the last chapter filled; it gains the columns. Register is the recorder or land registry you already search one parcel at a time. CRM receives only the twenty, each with the reason it was kept.
Every kept row says why, and every dropped row says why. Then the human can be found.
Ask: Of the rows you dropped last quarter, how many could you say today why they were dropped?
The book runs all twenty stages in order; the address here is chapter 3.
Chapter 4
Tool: Codex · Firecrawl MCP · Playwright MCP.
The owner is a company. Who do I call? The public record stops at the holding company. The name on the title does not answer the phone. So a six-person brokerage buys a name from a data vendor, and the sheet never says where it came from.
"Instead of an owner's name many property titles are identified as anonymous corporations, LLCs or holding companies. Piercing the corporate veil and digging up the contact information for the true owner has tremendous value." ClientLook, on theBrokerList, https://blog.thebrokerlist.com/how-to-find-a-commercial-property-owner/
That is the trade describing the stage as most people run it. Take the twenty from the last chapter, each with the entity recorded on the title. Search the entity name. What comes back is a registered address, sometimes an agent who files the paperwork, rarely a person. So the next tab is a data product, and a name arrives.
Read the same article to the end and something is missing. It gives no method. It lists five products and stops. The trade's own how-to for this stage is a list of things to buy.
Zero published prices Five products sell this stage by quote only, and not one prints what it charges. What you pay for is a name with no page behind it.
Source: ClientLook on theBrokerList, and the five vendors, checked 14 September 2026
Nobody has published an hours figure for this stage, and this chapter will not invent one. What is published is the shape of the shortcut. CoStar, Reonomy, ProspectNow, Catylist and TLOxp each sell the answer, and none of them prints a price.
The cost that matters is the missing page. When the next stage asks whether you may contact this person, and on what basis, a bought name has nothing to say.
Open Codex. Ask for the page. Map the company site with Firecrawl, scrape the people page, and only that page. A directory name is not a rung. When a page needs a click, Playwright opens it. Every name carries its page and date, or reads none.
Open Codex in the engine folder, where shortlist.csv from the last chapter sits: twenty
companies, each with the reason it is worth a call and the entity recorded on the title. Then
say what you want:
Read shortlist.csv. For every company, find its own website: the domain on
the recorded document if there is one, otherwise the site that names both
the company and the asset. Use Firecrawl to map the site and find the page
that lists its people: a team page, a leadership page, an about page with
names on it. Scrape that page and only that page. Take the name and title
of the person who runs the company. If the page needs a click to show the
names, open it in Playwright and take a snapshot instead. Never take a name
from a directory, a data vendor or a social profile. Record the name, the
title, the page it came from and the date you read it. Where no page names
a person, write none. Write people.csv, and report three counts: named from
the company site, none, and sites you could not find.
What comes back is a script, a run over the twenty and a report with three counts. people.csv
holds one row per company: the name, the title, the page and the date. Load it into the CRM. A
row that reads none is a company the next stage reaches another way.
Firecrawl maps a site and returns its pages as text; its hosted server runs without a key on a rate-limited free tier, enough for twenty companies. Playwright reads a page as a tree of what is on it, so names that appear after a click still come through.
The rule that matters is the one about the source. Book one in this series learned it on its own list: a name from the company's own page held up; a name from an aggregator did not. That is why the instruction reads one page and refuses the rest.
Three honest limits, which Codex will tell you about. A holding company that exists only to hold often has no site, and Codex writes none rather than guessing. A site with a contact form and no names is the same. And a company register may list officers, but whether the officer named is a reachable human or a service that files for the company was not tested for this book, so the chapter claims no rate. Use the register as a second door, recorded as its own rung.
Reaching them. The next stage reaches each named person honestly. It needs a name you can defend, with the page beside it. The number to read: companies resolved to a named human, over companies attempted, each with its source.
The next stage finds a way to reach each person honestly. It needs a name with a page behind it, because the page is what makes the first message defensible.
The number that proves this stage worked is companies resolved to a named human, over companies attempted, with the source beside each name, so a company-page name and any other name are never counted as the same thing.
Is this the right name? The page names a director. Whether that person decides about the asset, or only signs for it, is a judgement. A person rules once, writes the ruling beside the name, and the next run reads it.
The tool finds the name the company chose to publish. It cannot tell whether that person decides about this asset, or signs and refers upward. On a company of four the director is the owner. On a holding with eleven subsidiaries the director may be the person who forwards your message.
A person rules on each name, once, and writes the ruling into the same file the tool reads. The next run applies it without asking.
Nothing new to buy. CRM: the name, the title and the page it came from, three fields on every company. Browser: the people page, opened by the tool instead of by you. Sheet: the twenty from the last chapter, read in and written back with a name.
CRM gains three fields per company: the name, the title, and the page it came from. Browser is driven by the tool, which opens the team page you would have opened by hand. Sheet is the shortlist from the last chapter, twenty entities in, the people behind them out.
Every name with the page it came from, and every bought name left out. Then reaching them can be honest.
Ask: Of the names on your list today, how many came from a page the company itself published?
The book runs all twenty stages in order; the address here is chapter 4.
Chapter 5
Tool: Claude Code.
Look them up, then call the mobile. A licence to a database built for finding debtors. A junior broker with the owner name. A number by lunch. For a six-person brokerage the number sits in the CRM with nothing beside it to say where it came from.
"I've walked into Commercial Real Estate brokerages where every single broker had a license to a credit bureau" patrickrafferty, Hacker News, https://news.ycombinator.com/item?id=37230362
He goes on: "with many of the junior brokers using it daily to look up real estate owners to call their mobile phones. Obviously TLO knows there's no way a huge chunk of the CRE brokerage industry should be in their product on a daily basis if they were actually using a GLBA compliant use case... and they look the other way and find a way to monetize." Same post, same URL.
That is the concession: nothing cheap does the honest version, and something expensive does the other in seconds. Type in the name and a mobile comes back, from a product sold, the practitioner says, for a purpose the brokers do not have. It lands in the CRM looking like a number the owner gave you at a viewing, and nobody can tell the two apart.
The honest lane is narrower, and wider than residential advice admits.
$53,088 The fine the FTC prints, per violation, for calling a US number that was on the registry. One number with no source beside it is one call you cannot explain.
Source: FTC Q&A for telemarketers on the Do Not Call provisions, inflation adjusted January 2025, read 14 September 2026
The licence is the visible cost, and no vendor prints it. The real cost is the call you cannot explain. The FTC's page for telemarketers says a violation is "subject to a fine of up to $53,088" (https://www.ftc.gov/business-guidance/resources/qa-telemarketers-sellers-about-dnc-provisions-tsr-0). That is one market's figure. Every market asks its own version, and a record answers each.
Open Claude Code. Ask for the basis. Every number carries where it came from and what permits the contact: published, given to you, or opted in. A number with no basis is held, never dialled. Beside each: its source, its date, the hours it may be contacted in.
Open Claude Code in the engine folder, beside people.csv from the last chapter and your CRM
contacts exported as crm-export.csv. Then say what you want:
Read people.csv. For every person, find a way to reach them, stopping at
the first rung that holds: a number or address the business itself
publishes; then one this person gave us, in crm-export.csv with its
date; then a WhatsApp opt-in we hold, with the date and their words.
Record the rung, its source and its date. Never take a number from a
bought database, a credit bureau product or a scraped list, and never
guess one. Add two blank columns for a person to fill: registry_checked
and hours. Write reach.csv with a source and a basis on every row,
holding.csv for the rest, and report four counts: published, given,
opted in, none.
What comes back is a script, a run and four counts. reach.csv carries a rung, a page or
message and a date on every row.
The hinge is the first rung. The FTC's own page says the US registry exempts "Most phone calls
to a business made with the intent to solicit sales from that business" (same URL as above). A
consultant calling a company about its premises is doing something different from an agent
calling a homeowner, and the company's published number is the widest honest lane this reader
has. The build does not decide what that sentence means for you. It writes the rung, dates
registry_checked when a person runs whatever check your market asks for, and flags any row
older than a month.
For WhatsApp the rung is Meta's. The Business Messaging Policy reads: "You may only contact people on WhatsApp if: (a) they have given you their mobile phone number; and (b) you have received opt-in permission from the recipient confirming that they wish to receive subsequent messages or calls from you" (https://whatsappbusiness.com/policy/). An opt-in someone else collected is never written as yours. The free lane, a client on your own phone, is named once, as the warning: the Business Terms forbid applications that "interact with our Business Services without our prior written consent" (https://www.whatsapp.com/legal/business-terms).
One honest limit, which Claude Code will tell you about: it cannot rule on whether a basis is enough in your market. A reader in Dubai meets different questions from a reader in Texas: consent before a message on a social platform, the hour of the day, naming yourself and your purpose at the start. The build answers none. It records the consent, the source and the hours, and chapter 6 opens every message with your name and why you are writing.
The first message. The next stage writes one message per person, and its first line depends on the basis: published, given, or opted in. The number to read: contacts with a recorded source and a recorded basis, against contacts held.
The next stage writes fifty messages, and each opens on why the contact is permitted. A message to a published line reads differently from one to a number the owner gave you at a viewing. The basis column lets the writer choose without asking; the hours column tells the sender when not to.
The refusal. Whether to contact at all. Whether a source permitted for a purpose you do not have is off the table. A person rules once, and the rule is written where the next run reads it.
The tool sorts people into published, given, opted in and none. It cannot tell whether a switchboard reaches the owner or a receptionist who never passes it on.
Nor can it make the refusal. Not opening the database in the quote above is the one job here no script does. A person rules on it once, writes the ruling into the file the tool reads, and the next run applies it.
Nothing new to buy. CRM: the source, the basis, the date and the hours, four fields on every person. Phone: the line you already dial from, only for rows with a basis. WhatsApp Business: the opt-in recorded before any template goes out.
CRM gains four fields per person: the source, the basis, the date last checked, the hours.
Phone is the line you already call from. Nothing on holding.csv is dialled.
WhatsApp Business holds the opt-in, dated, before chapter 8 sends.
Every number with its source beside it, and the ones with none held back. Then the first message can be defended.
Ask: Of the numbers your team called last week, how many could you say where they came from?
The book runs all twenty stages in order; the address here is chapter 5.
Chapter 6
Tool: Codex · Google Sheets MCP · Filesystem MCP.
A template, and a new top line. A letter pack bought once, edited fifty times. Hope you are well. Just checking in. For a six-person brokerage the fifty read like one letter sent fifty times, because they are.
Generic sequencers are cheap and everywhere, and none of them knows a building from a business. The trade's own answer to this stage is a product category: prospecting-letter template packs, sold one-off and typically under $100, by Wise Pelican, The Close and others. They are the reason every letter an owner receives reads the same.
By hand, that means picking the nearest letter, changing the name and the street, and sending. You can write five good ones. You cannot write fifty, so the top line changes and the rest does not.
The people on the other end have noticed:
"In no world would I ever believe that a cold email was significantly personalized/targeted, except if the overall content were highly specific to me." buu700, Hacker News, https://news.ycombinator.com/item?id=28148221
Five hundred minutes Fifty messages at ten minutes each. Both numbers are yours; the arithmetic is a working day. So the template wins, and the owner gets the same letter as the street.
Source: modelled
No published figure says how long this stage takes, and this book will not invent one. The sum is modelled from two numbers only you can supply: your weekly volume, and your minutes per message. The template industry exists because a day is rarely spent on it. Direct-mail services print what you hand them; none writes.
Open Codex. Ask for your voice. The twenty come in from the sheet with their reason. Your own past messages come in from disk as the voice. Every draft carries one fact from the row and nothing the row does not hold. You read each before anything sends.
Open Codex in the engine folder. The Owners sheet from chapter 3 is there, with its reason
column, and reach.csv from the last chapter, with each person's basis and hours. Make one
folder now, voice: twenty or thirty messages you wrote and would send again, one to a
file.
Connect two servers. Google Sheets MCP, the community server taylorwilsdon/google_workspace_mcp, reads the rows and writes the drafts back; budget fifteen minutes for the Google sign-in. The Filesystem server from the reference repo reads the voice folder. Then say what you want:
Read the top twenty rows of the Owners sheet by score, with the reason
column, and read reach.csv for each person's basis and hours. The voice
folder holds messages I wrote myself; the drafts must sound like them,
my length and my openings. Write one message per row. Open with my name
and why I am writing, in the words the basis allows. The second sentence
is the one fact in the reason column, stated as the record states it,
with no adjective on it. Never add a fact that is not in the row. Never
write hope you are well or just checking in. End on one question about
the fact. Write each draft in a draft column beside its row with the fact it
used; leave the sent column blank. Report two counts: drafts
written, and rows where the reason was too thin to write from.
What comes back is a script, a run and two counts. You read the twenty before the afternoon is out, and the sent column is the button the next chapter presses.
The rule that carries the chapter is the second sentence. A recorded maturity, a tenure, a confirmed expiry: each has a public page behind it. The strongest objection to machine-written outreach is the recipient's:
"I open emails because I believe you spent time on me, which is precious, so I reply. If an AI generates cold emails, there's no real time spent, making personalization feel deceptive, which is bad for user experience." sherwinx, Hacker News, https://news.ycombinator.com/item?id=40876341
The only answer that survives it is a fact that is true and defensible. The reason column holds one; a template pack cannot.
The nearest public build is OpenOutSend (https://github.com/eracle/OpenOutSend, MIT, eight stars, pushed September 2026). It writes from a person's profile text, company and title, under a tone rule that reads "short and specific, like a real person wrote it, not salesy". It is built for a different trade: it needs a paid candidate list from its sister tool, and a read of its source found no property vocabulary.
Three honest limits, which Codex will tell you about. The drafts sound like the voice folder, so twenty messages you regret produce fifty more. A row whose reason is thin gets no draft, because a draft from nothing needs an invented fact. And no tool can tell whether you would defend the fact in a call.
Sending. The next stage picks the channel each person answers on and sends the drafts you have read. The number to read: drafts carrying a fact from the record, over drafts sent, and how many you edited.
The next two chapters pick the channel and send. A draft you have not read never gets a sent date.
Two numbers prove this stage worked. Messages carrying a specific fact from the record, over messages sent. And the count of drafts you edited before sending, because a falling edit rate is the only honest sign of your voice arriving.
Read it before it goes. The tool writes the draft. Whether you could defend the fact in it on a call is your call. And whether this person should get a call instead of a letter is a ruling only you can make.
Two things stay. Reading every message before it goes, because nothing in this book sends without a person. And the judgement that a particular owner should get a call and no letter: a name you know, a building you have been inside.
Write call in the channel column, once, and the next chapter's sender skips that row.
Nothing new to buy. Sheet: the twenty rows in, a draft beside each, the fact it used, a blank sent column. Folder: your own past messages, read by the tool as the voice sample and never sent. CRM: gets the message only when a send is logged, in the next stage.
Sheet gains three columns: the draft, the fact it used, and sent, still blank. Folder holds your own messages, read and left where they are. CRM stays out until a send is logged. The pipeline records sends, never drafts.
Fifty messages on the sheet by Tuesday afternoon, each carrying one fact from the record, each read by you. Then sending them is one button.
Ask: Of the last fifty messages you sent, how many carried a fact the owner could check?
The book runs all twenty stages in order; the address here is chapter 6.
Chapter 7
Tool: Claude Code · Gmail MCP · WhatsApp Cloud API MCP · HubSpot MCP.
The reply lands on your phone. Fifty messages went out by email. The answers come back on WhatsApp, on your own phone, and stay there. For a six-person brokerage that is a phone per person and a CRM that says nobody replied.
Two free products already run the messaging rail properly. DeskcommCRM (https://github.com/melgarafael/DeskcommCRM) is a self-hosted WhatsApp CRM, 2,457 stars, MIT, pushed on 14 September 2026. wacrm (https://github.com/ArnasDon/wacrm) is 2,322 stars, MIT, pushed the same day. Do not build a WhatsApp CRM. Clone one; it costs nothing a month.
Then run the grep. In both repos landlord matches zero files, viewing zero, valuation zero,
mortgage zero. Neither knows what a property is or who owns it. The rail is solved and free.
The join between the rail and the owner is this chapter.
The market picked the channel before you did: Bayut sorts its leads as "Email, SMS, Phone, WhatsApp and Chat" (https://www.bayut.com/agentportal/best-features-profolio-offers/). So the email you sent gets answered on a number. The reply sits on one phone, the CRM shows an email sent and nothing after it, and the call that follows is written nowhere.
You will not read here what share of enquiries arrives on WhatsApp: both portals report your own split to you, and nobody publishes the total.
24 hours The window that opens when an owner messages you. Inside it every reply is free. Outside it the same reply is a pre-approved template, priced per message delivered.
Source: Meta, the WhatsApp Cloud API pricing and send-messages developer pages, read 14 September 2026
No hours figure exists for this stage; what Meta publishes is a clock.
"When a WhatsApp user messages you or calls you, a 24-hour timer called a customer service window starts." Meta, https://developers.facebook.com/docs/whatsapp/cloud-api/guides/send-messages
"When the window closes, you can only send pre-approved template messages." Meta, same page
"You are only charged when a template message is delivered" Meta, https://developers.facebook.com/docs/whatsapp/pricing
So a reply on a phone nobody watches passes hour twenty-four, and the follow-up becomes a template you pay for. Meta prices those on rate cards this chapter has not read, so it prints no figure.
Open Claude Code. Ask for one inbox. Email replies arrive through Gmail, WhatsApp replies through a Cloud API webhook. Both land on one CRM record per owner. The personal-session lane is named once and never used. The terms you accepted forbid it.
Open Claude Code in the engine folder. Connect Gmail
through taylorwilsdon/google_workspace_mcp, the server that read your sheet, with fifteen
minutes for its Google OAuth setup. Connect the CRM through its own server, HubSpot's at
mcp.hubspot.com; Pipedrive and Zoho publish their own.
WhatsApp is two lanes, and Meta publishes no MCP server for either. The first logs into your own phone by QR code through a reverse-engineered client; lharries/whatsapp-mcp, 6,269 stars, has had no push since July 2025. The Business Terms you accepted say a company must not "develop or use any applications that interact with our Business Services without our prior written consent" (https://www.whatsapp.com/legal/business-terms).
The second lane is Meta's Cloud API: a business number and a WhatsApp Business Account, with templates approved before they are sent. The build is a send endpoint and a webhook receiver, the shape of marco2901/whatsapp-mcp-server; copy the shape rather than depend on a repo with zero stars. Twilio is the same lane with Twilio in front. Then say what you want:
Read people.csv and the CRM. For every owner we messaged last chapter,
record the channel and the date on their record. Connect Gmail: when a
reply arrives from an address on the list, log it as an email activity
on that owner's record, linking the thread. Stand up a webhook receiver
on the WhatsApp Cloud API for our business number: when an owner writes,
store the message, log it as a note on the same record, and stamp the
time the 24-hour window opened. Never touch a personal WhatsApp session.
A reply from a number the CRM does not hold goes on a list for me; never
guess the owner. Report three counts: replies filed, replies with no
record, and windows open now with no answer from us.
What comes back is a script, a webhook that stays up, and three counts. Each owner's record carries both threads as dated activities. The third count is the morning one.
Two honest limits, which Claude Code will tell you about. An owner who has your personal number keeps writing to it until you move them. And the first message to an owner who has never written to you is a template with prior opt-in, which is the next chapter.
The reply, in one inbox. The next stage messages fifty owners on WhatsApp from the same business number and reads replies off the same record. The number to read: replies answered inside the window, over replies received.
The next chapter sends fifty owners a WhatsApp message in a morning, from the business number, the webhook and the record this chapter builds; a reply that lands nowhere is a priced message spent for nothing.
The number that proves this stage worked is replies answered inside the 24-hour window, over replies received.
The conversation itself. The tool files the reply. The answer to an owner selling the building they built is written by a person. Automation inside the window is permitted. The escalation path to a person is the condition.
Meta's rule, in one sentence:
"You may use automation when responding during the 24-hour window, but must also have available prompt, clear, and direct escalation paths." WhatsApp Business Messaging Policy, https://whatsappbusiness.com/policy/
The policy asks for no bot announcement; it asks for the door to a human. The machine here files the reply and stamps the clock. Whoever reads the record decides whether to answer with a template or a call; a property sale is the largest emotional transaction most people make.
Which number becomes the business number is also a person's ruling, made once.
One business number. Nothing else new. CRM: one record per owner, the email thread and the WhatsApp thread on it as dated activities. Gmail: the email replies, read by the tool through the same server that reads your sheet. Number: a business number on the Cloud API, direct or through Twilio; your own stays yours.
CRM gains an activity per reply, whichever channel carried it. Gmail is read by the same server as the sheet from chapter three. Number is the business number Meta requires, real or virtual.
One record per owner, every reply on it, whichever channel it came on. Then the fifty can go out.
Ask: Of the replies you received last week, how many can you find in the CRM today, and how many live on a phone?
The book runs all twenty stages in order; the address here is chapter 7.
Chapter 8
Tool: Codex · WhatsApp Cloud API MCP · Twilio WhatsApp.
Fifty owners, one phone, one morning. The messages from chapter 6 go out one paste at a time, from the phone the whole business runs on. For a six-person brokerage the shortcut is a free server that logs into that phone. No templates, no opt-in record.
The rail is Meta's, and Meta publishes the rules. On the official lane a product already does this stage at per-message pricing: a business number, an approved template, a fee per message delivered. What no product holds is the rules, read before the morning and after it: the build.
Chapter 7 laid out the two lanes; this chapter sends on the official one. The shortcut is the other: lharries/whatsapp-mcp, 6,269 stars and no push since July 2025 (https://github.com/lharries/whatsapp-mcp). The Business Terms you accepted say a company must not "develop or use any applications that interact with our Business Services without our prior written consent" (https://www.whatsapp.com/legal/business-terms), and the Messaging Policy says that for "messaging people at scale in an unauthorized manner" Meta has "the right to limit or remove your access to WhatsApp Business Services" (https://whatsappbusiness.com/policy/). No number attaches to that sentence, and this book will not invent one. Named once; never used.
Fifty paid messages One template per owner, charged only when delivered, at a rate Meta prints per currency on its own card. The cost with no line on the card is the number itself.
Source: Meta, WhatsApp Business Platform pricing pages, read 14 September 2026
"Effective July 1, 2025, Meta charges on a per-message basis" (https://developers.facebook.com/documentation/business-messaging/whatsapp/pricing), and "You are only charged when a template message is delivered" (https://developers.facebook.com/docs/whatsapp/pricing). The rate is a card per currency at https://business.whatsapp.com/products/platform-pricing#rates. This chapter prints no figure; every per-country price found came from a company selling the sending.
A number that stops working is the one every reply from chapter 7 lands on.
Open Codex. Ask for the morning. A thin server on the Cloud API: the template tools, and two that read the quality rating and the sending limit. Templates approved the day before. Fifty sends. Every failure written by its error code, and a capped row never retried.
Open Codex in the engine folder, beside reach.csv and the chapter 6 messages. Meta
publishes no MCP server, so the build is a thin one of yours, a handful of HTTPS calls, in
the shape of two one-day community repos: tkhattar14/whatsapp-business-mcp (template and
analytics tools; https://github.com/tkhattar14/whatsapp-business-mcp) and
marco2901/whatsapp-mcp-server (a send and a webhook receiver;
https://github.com/marco2901/whatsapp-mcp-server). Read their tool lists, depend on neither,
and say what you want:
Build a thin MCP server on the WhatsApp Cloud API in the shape of the
two repos above: create a template, read its status, send it, receive
the webhook, read the quality rating and the messaging limit. Today:
submit the chapter 6 message as a marketing template with a variable for
the owner's name and one for the building, and stop until its status
reads APPROVED. Tomorrow: print the rating and the limit before sending
anything. Send only to rows in reach.csv whose basis is opted in, inside
the hours the row allows, one message per owner. Write every send and
every failure to sends.csv with its error code. On error 131049 mark the
row capped; never retry it. At the end print the rating again beside the
morning's. Report four counts: delivered, capped, failed otherwise,
replied.
What comes back is a server, a run and four counts.
Every rule it obeys is on a Meta page. "You can only send messages to WhatsApp users who have opted in to receiving messages from you" (https://developers.facebook.com/docs/whatsapp/cloud-api/guides/send-messages), so the run reads the chapter 5 basis column and nothing else. "You may only initiate conversations using an approved Message Template" (https://whatsappbusiness.com/policy/), and "Templates are automatically reviewed upon creation or after editing" (https://developers.facebook.com/docs/whatsapp/business-management-api/message-templates), a review that can take up to 24 hours, so the template goes in the day before.
The cap shapes the morning. "The per-user marketing limit adapts automatically over time based on a person's recent engagement levels" (https://developers.facebook.com/documentation/business-messaging/whatsapp/templates/marketing-templates/per-user-limits). It is the recipient's, shared with every business messaging them; when it is spent the send fails with error 131049 and nothing queues. Your own limit starts at 250 unique recipients a day and rises only while the quality rating holds (https://developers.facebook.com/docs/whatsapp/messaging-limits), so the run reads it before and after.
Two honest limits, which Codex will tell you about. The fifty voices of chapter 6 become one reviewed text with two variables. And marketing templates never reach US numbers, while the cap applies in full in the UAE and not in the EEA, the UK, Japan or South Korea (same page).
Twilio is the on-ramp if you would rather not stand up a Meta app: "Send and receive WhatsApp messages using the WhatsApp Business Platform and Twilio APIs" (https://www.twilio.com/docs/whatsapp), the same rules, its own fee on top.
The reply. An owner who writes back opens a window where every message is free and nothing counts against the cap. The number to read: replies over templates delivered, by Friday. Sends are the cost. Replies are the result.
A reply changes the rules. "When a WhatsApp user messages you or calls you, a 24-hour timer called a customer service window starts" (https://developers.facebook.com/docs/whatsapp/cloud-api/guides/send-messages), and inside it "All non-template messages are free" (https://developers.facebook.com/docs/whatsapp/pricing). Marketing sent inside it does not count toward the cap (per-user limits page, above). Chapter 11 runs the conversation there.
The number that proves this stage worked is replies over delivered. A high capped count means other businesses spent that owner first.
The words in the template. Meta reviews it and fifty owners read it. Its category, and whether it earns their attention, is a judgement. A person writes it once, the day before, and the run sends nothing else.
The server submits the text it is given. It cannot say whether that text is marketing or utility, and the category sets the price and the cap, so a person rules on it. Nor whether a chapter 5 opt-in is strong enough for a marketing template. And when the evening rating sits below the morning one, a person decides whether Wednesday runs.
A fee per message, nothing to install. WhatsApp Business: the number, the account, the template, the rating read before and after. CRM: one row per owner with the send, the error code and the reply. Sheet: reach.csv in, sends.csv out, capped rows marked for the next run.
WhatsApp Business is the number and the account.
CRM gains sent when, failed why, replied when.
Sheet is reach.csv in, sends.csv out.
Fifty owners messaged by approved template, and the number still answering clients on Friday. Then the reply can be the objective.
Ask: Which number did your last fifty WhatsApp messages go out from, and what would stop if it did?
The book runs all twenty stages in order; the address here is chapter 8.
Chapter 9
Tool: Claude Code · Gmail MCP · Playwright MCP · HubSpot MCP.
The enquiry lands. Nobody is awake. A portal notification at eleven at night, into an inbox that opens at nine. The buyer is still awake, still looking. For a six-person brokerage the morning starts with a pile, and the pile is read in the order it arrived.
Portals and CRMs deliver the enquiry. None of them answers it. Follow Up Boss pulls Zillow and Realtor.com leads into a record for $69 a user a month; the UAE CRMs sell Bayut and Property Finder capture as their headline. Ingestion is bought. What lands in the record at eleven at night is still there, unanswered, at nine.
So the stage runs by hand, on volume:
"we get spammed with 100+ emails a day so pick up the phone or text" Rose Higgens, https://www.biggerpockets.com/forums/311/topics/941560-what-am-i-doing-wrong-all-agents-so-far-have-been-flaky-at-best
The enquiry comes four ways: a portal email, a message in the portal's own inbox, a WhatsApp on a personal phone, a referral spoken aloud. Only the first two are systems.
917 minutes The average wait before a broker replied, across 384 brokers in eleven states, secret-shopped. Nearly half of the enquiries were never answered at all.
Source: WAV Group with the Weichert Lead Network, Agent Responsiveness Study, 13 January 2014
Researchers posed as buyers. Verbatim: "48% of buyer inquiries were NEVER responded to." Among the rest, "Average response time was 917 minutes (or 15.29 hours)", with 1.5 call-backs and 2.07 emails after first contact. https://www.wavgroup.com/2014/01/13/agent-responsiveness-study-reveals-critical-flaws-in-real-estate-lead-response/
Two things to print beside it. The study is twelve years old. And Weichert's own lead division co-produced it and is the contrast case inside it. The number is usually credited to the wrong people and the wrong year; it is this one.
Fast replies go with more conversations in every audit, and nobody has tested whether the speed causes it. This chapter builds on the correlation and says so.
Open Claude Code. Ask for the reply. Gmail reads the portal email; Playwright opens the portal inbox with no API. The reply goes back the way it came. It asks permission and the three questions. HubSpot gets the person and the note within the hour, whatever the hour.
Open Claude Code in the engine folder. Connect the mailbox the portal writes to: for Gmail,
the community server taylorwilsdon/google_workspace_mcp, with fifteen minutes budgeted for the
Google Cloud OAuth setup (the GongRzhe Gmail server the lists name is archived). For a
portal inbox with no feed, Microsoft's Playwright MCP, headless, with a saved login. For the
CRM, HubSpot's own remote server at mcp.hubspot.com. Write reply.md once: an acknowledgement
in your words, the consent line, and the next chapter's three questions, when, how much, and
whether the money is arranged. Then say what you want:
Every ten minutes, read the inbox for new portal enquiries, and read the
portal inbox in Playwright with the saved login. Tell me the total before
you do anything. Reply to each within the hour, on the channel it
arrived on: email by email, a portal message in the portal's own reply
box. Use reply.md, filled with the listing and their name, nothing else.
Never reply on WhatsApp. In HubSpot, create the contact if none matches
the email or phone, and add a note: the listing, what they wrote, when
it landed, when you replied. Leave the timeline, price range and
pre-approval fields blank until they answer; never fill them from a
guess. Report three counts each morning: landed, replied within the
hour, still waiting.
What comes back is a script, a schedule and three counts. At nine the morning starts with a list: who wrote overnight, what they were sent, who has answered. The reply is yours, written once; the tool fills in the name and the listing.
Why never WhatsApp. A portal email has not opened a WhatsApp window, so the first WhatsApp message to that person is a paid template, approved before the enquiry existed. That build is chapter 8.
Three honest limits, which Claude Code will tell you about. A saved portal login expires and a portal page changes shape, so a run that finds zero enquiries reports zero, never silence. HubSpot blocks notes if the account has sensitive data turned on. And two channels are not read here: a WhatsApp on a personal phone, since the book never reads WhatsApp Web, and a spoken referral.
Qualifying it. The next stage tells a buyer from a browser in three questions. It needs the questions asked, and the answers arriving. The number to read: minutes from enquiry to first reply, with the count of enquiries that got none beside it.
The next chapter reads what the buyer answered and fills the three fields from it, in the buyer's words, so no field is ever a guess.
The number that proves this stage worked is the median minutes from enquiry to first reply, across every channel, with the count that received none beside it. A median alone hides the half that got nothing.
Whose hour is this? Whether an enquiry gets your own morning or goes to a colleague is a judgement, made after the reply, never before. A referral arrives inside a relationship. It is answered by a person, from the first line.
The reply at eleven at night is a door held open. Who comes through it is yours to judge; the tool never disqualifies anybody. A blank field means nobody has answered yet, never a browser.
"Would you give up on them after they don't return your ONE phone call? Or, decide in advance that they're not a 'good lead' because they didn't leave a phone number?" Dean Jackson, reposted by Julie Martin, https://activerain.com/blogsview/1270593/how-to-tell--real--buyers-from-tire-kickers--one-question-
And the referral. Someone who trusts you said it aloud. The night reply would spend that, so a person answers it, the same day.
For balance, one agent:
"I always think these threads are interesting because I always get call backs and email backs." Russell Brazil, https://www.biggerpockets.com/forums/48/topics/715153-re-agents-are-slow-to-or-dont-call-back
Nothing new to buy. Mail: the inbox the portal writes to, read by the tool every ten minutes instead of at nine. Portal: the inbox behind the login, opened by the tool, the reply box filled by the tool. CRM: the person and the note, written within the hour of the enquiry, whatever the hour.
Mail is the inbox the portal already writes to, read through the night. Portal is the inbox behind your login, opened by the tool instead of by you. CRM is HubSpot, or Pipedrive, Zoho or Follow Up Boss through their own servers; it gains the person, the note, and three blank fields.
Every enquiry answered inside the hour, and every one that was not, counted. Then qualifying can begin by morning.
Ask: Of the enquiries that landed last night, how many had a reply before you woke up?
The book runs all twenty stages in order; the address here is chapter 9.
Chapter 10
Tool: Codex · Memory MCP · HubSpot MCP.
Five questions in five minutes. The trade asks them in a script, by phone, after asking permission to ask. The answers land in no field. For a six-person brokerage the shortcut is a form, and a form is where a buyer stops answering.
Every public qualifier is a form. Nine public repositories were opened at source for this book; none reads a conversation that happened. The fields already sit in the CRM you pay for. The gap is that the answers are given on a phone.
By hand, the trade asks a script. An agent in Northern Virginia publishes his, timed at about five minutes; two of its questions, the date and the lender, are the two this chapter keeps. It opens by asking permission:
"Before we start looking at homes, do you mind if I ask a few quick questions? It just helps me make sure I only show you places you will actually love, and that I do not waste your time. Fair enough?" Saad Jamil, Jamil Academy, https://www.jamilacademy.com/blog/pre-qualification-script-how-to-qualify-buyers
The trade agrees on the fields too. A buyer qualification form on Jotform, cloned 1,851 times (https://www.jotform.com/form-templates/real-estate-buyer-qualification-form), opens with Purchase Timeline, Price Range and Lender Pre-Approval Status, in that order. It asks for the money before it asks for a name.
"The very best way to tell the real buyers from the tire-kickers is to treat EVERY ONE OF THEM like they're a real buyer until they prove otherwise vs. treating them like they're a tire-kicker until they prove they aren't." Dean Jackson, reposted by Julie Martin, Port City Realty, Mobile AL, https://activerain.com/blogsview/1270593/how-to-tell--real--buyers-from-tire-kickers--one-question-
About five minutes One qualification call, timed by the agent who publishes his script. Dials that never connect are not counted. Nobody has published how many enquiries are browsers, so this book prints no share.
Source: Saad Jamil, Jamil Academy, read 14 September 2026
The five minutes is the call; the dials that never connect are where the week goes, untimed. Every published share of browsers traced back to a company selling leads, so none is printed here.
"consumers tend to be far more flaky than agents. We can't discern a seasoned buyer from an energy vampire" Rose Higgens, agent, https://www.biggerpockets.com/forums/311/topics/941560-what-am-i-doing-wrong-all-agents-so-far-have-been-flaky-at-best
Open Codex. Ask for the three fields. It reads the thread from the last chapter and writes timeline, finance and your third field, in their words. What was not said is written as unknown, never guessed. Nobody is sent a question. Every field carries its message.
Open Codex in the engine folder. The enquiry chapter 9 answered, and every message since, sits
on the contact in the CRM, with three fields left blank. Connect two servers. HubSpot's remote
server reads and writes contacts and the notes, emails and calls on them
(https://developers.hubspot.com/ai-tools/mcp). The Memory server from the protocol's reference
repository holds what each person said
(https://github.com/modelcontextprotocol/servers). Write fields.md once: three field names,
and what counts as an answer to each. The first two are the form's: the timeline, and where the
money stands. The third is yours; the form offers Price Range, chapter 9's reply asked how much,
and a commercial reader may want the intended use instead. Then say what you want:
Read every contact whose enquiry came in this week, with the whole
thread. Fill the three fields in fields.md, in the person's own words,
with the message each came from and its date. Where they said nothing,
write unknown. Never guess, and never send them a question. Record
what each person said in Memory, so the next run reads only new
messages. Where all three are filled and the timeline is inside a
year, set route to viewing; otherwise follow-up, with the reason in
their words. Report three counts: all three filled, some, none.
What comes back is a script, a run and three counts: on each contact, three sentences the person wrote, a route, and its reason.
The reason stays because the public builds throw it away: the best public attempt decides by matching substrings after the model finishes (https://github.com/Nishkal08/Real_Estate_Agentic_CRM-Whatsapp-Enabled), and the deepest public CRM writes one field, temperature, and discards its reasoning (https://github.com/InsulaCRM/InsulaCRM).
Three honest limits, which Codex will tell you about. A yes to the lender question from someone who used an online calculator reads as yes; only a person hears the difference. So does ASAP from someone with nine months left on a lease. And a HubSpot account with sensitive data turned on blocks the activities its server reads (https://developers.hubspot.com/changelog/remote-hubspot-mcp-server-is-now-generally-available), so the thread comes from the mailbox chapter 9 connected.
Routing them. The next stage puts each enquiry in front of a person, or into the long follow-up, from three fields. The number to read: enquiries with all three fields filled within two days, beside the count with none.
A viewing route goes to chapter 12, where a person claims it or it is taken back. A follow-up route goes to chapter 15, the client who buys in two years. A browser is that person, sent there with the reason beside them, and nobody has failed.
The number that proves this stage worked is enquiries with all three fields filled within two days, beside the count with none; never a rate alone. A rising fill count with a falling reply count means the machine has started guessing.
The permission, and the third question. Asking whether you may ask is a relationship move. So is hearing that a stated budget is a hope. A person picks the third field once, writes it where the run reads it, and decides who gets the Saturday.
The tool writes down what was said. It cannot ask "Fair enough?", because that line is the
agent asking to be trusted, and it cannot hear that a price given as one round number is a
wish. So the build disqualifies nobody, as Dean Jackson asks. A person decides who is worth the
Saturday, and rules the third field once, in fields.md.
Nothing new to buy. CRM: three fields on every enquiry, each with the message it came from, and a route. Memory: what each person said, so the next run reads new messages only. WhatsApp: the thread stays where it is. This stage sends nothing.
CRM gains three fields per enquiry and a route with its reason; HubSpot here, or Zoho, Pipedrive or Airtable through their own servers. Memory keeps what each person said; a second run reads only what is new. WhatsApp is untouched; the window from chapter 8 stays open for chapter 11.
Three fields on every enquiry, in their own words, and nobody turned away by a form. Then routing them can happen by itself.
Ask: Of the enquiries you answered this week, for how many could you say when they mean to buy and whether the money is there?
The book runs all twenty stages in order; the address here is chapter 10.
Chapter 11
Tool: Claude Code · WhatsApp Cloud API MCP · Calendly MCP.
The buyer writes. You type back. A message lands on the business number at ten at night. Someone answers by thumb, asking the questions from memory. For a six-person brokerage that is six evenings and six versions of the questions, in threads nobody else can read.
Nothing runnable reads a property conversation. Chapter 10 opened nine public repositories at source, and none reads one that happened. So there is no product to concede; the first conversation on WhatsApp is typed by a person in the evening.
The channel and its two lanes are chapter 7; this chapter answers on the business number and the webhook chapter 8 stood up, never on a personal session.
By hand, the conversation is chapter 10's phone script, typed. The trade asks one question at a time, and each carries its reason:
"In a perfect world, when would you love to be in your new home? Is there anything driving that date, like a lease, a school year, or a job start?" Saad Jamil, Jamil Academy, https://www.jamilacademy.com/blog/pre-qualification-script-how-to-qualify-buyers
At ten at night the same questions go into one message, which is a form by another name, and the viewing is agreed in a thread on one phone.
Zero, per message Every reply inside the window is free, whoever writes it. The customer resets the clock each time they answer. What it costs by hand is an evening, and nobody has measured that.
Source: Meta, the WhatsApp Cloud API pricing and send-messages developer pages, read 14 September 2026
The window opens only when the customer writes, never when you do:
"When a WhatsApp user messages you or calls you, a 24-hour timer called a customer service window starts." Meta, https://developers.facebook.com/docs/whatsapp/cloud-api/guides/send-messages
"If the user messages or calls you again before the timer expires, the timer resets to 24 hours." Meta, same page
"All non-template messages are free" Meta, https://developers.facebook.com/docs/whatsapp/pricing
A conversation that keeps the buyer answering never leaves the free window; one that goes quiet for a day comes back as a paid template. No response-time figure is printed here; none is sourced.
Open Claude Code. Ask for the thread. The webhook receives it. Inside the window the model asks the three questions, one at a time, in your voice. When the three are answered, Calendly makes the link. A price, a hard question or anger goes to a person.
Open Claude Code in the engine folder. The number, the webhook and the message store are chapter 8's thin server; this chapter adds a reader. The shape, a webhook, a store and two send tools, is marco2901/whatsapp-mcp-server (https://github.com/marco2901/whatsapp-mcp-server): credit it, depend on nothing with zero stars.
Connect Calendly through its own hosted server at mcp.calendly.com, which carries a scheduling
links group (https://developer.calendly.com/docs/mcp/calendly-mcp-server). Write
conversation.md once: your first line, the permission line, chapter 10's three questions,
and the four things that end the machine's turn. Then say what you want:
When a message arrives on the webhook from a number with an open window,
answer inside the window and never after it closes. Use conversation.md:
my first line, then permission, then the three questions from chapter 10
one at a time, in my words, waiting for each answer. Write each answer on
the contact in their words, with its message. When all three are answered
and the route reads viewing, ask Calendly for a scheduling link and send
it. Stop and hand the thread to me the moment they ask a price, ask
something the listing does not answer, sound angry, or ask for a person:
tell them someone will reply. Log every message, both directions, on the
contact. Report three counts each morning: opened, links sent, handed to
a person.
What comes back is a script that watches the store, one thread per buyer, and three counts. The link books the viewing, and Calendly reports the booking to the contact.
Three honest limits, which Claude Code will tell you about. Calendly's server needs a client
that registers itself: "If your MCP client prompts you to paste in a client_id and
client_secret, it does not support DCR and will not work with Calendly MCP" (same page).
cal.com's official server is unpushed since May 2025; its link comes from its API v2. And a
yes to the money question, typed at ten at night, is the yes chapter 10 warned about.
The viewing. The next stage makes sure a handed thread does not die unread. The one after confirms the viewing. The number to read: conversations that ended in a link or a person, over conversations opened.
Chapter 12 makes sure a person picks up each thread this chapter hands over. Chapter 13 confirms the viewing the morning after, outside the window, as a template.
The number that proves this stage worked is conversations ending in a link or a handoff, over conversations opened, with the silent count beside it.
The door to a person, and the price. Meta permits the automation and requires the escalation path. Nothing in the policy asks you to announce a machine. Whether to say so anyway is yours to decide. This book says so, in the first line.
The licence for this chapter is one clause:
"You may use automation when responding during the 24-hour window, but must also have available prompt, clear, and direct escalation paths." WhatsApp Business Messaging Policy, https://whatsappbusiness.com/policy/
The policy was read for a rule that a machine must announce itself; there is none, and the widely repeated disclosure rule is not Meta's. What Meta requires is the door. Four things open it: a price, which the machine never quotes; a question the listing does not answer; anger; and the words "can I talk to someone". Each hands you the thread.
Whether the first line says a machine is writing is your choice. This book says it, and that a person is one message away; a buyer who finds out later arrives distrusting you.
One calendar link. Nothing else new. Number: the business number and webhook from chapter eight, answered inside the window by the model. Calendar: Calendly through its own hosted server, making the link and reporting the booking. CRM: every message, both directions, on the contact, as chapter sixteen keeps it.
Number is chapter 8's business number on the Cloud API. Calendar is Calendly through its own server, or cal.com through its API. CRM gains the thread, both directions, dated, on the contact chapter 9 created.
The whole first conversation, in your words, inside the free window, and the viewing on the calendar before you woke up. A person still holds the door.
Ask: Of the buyers who wrote to you last week, how many were offered a viewing time inside the hour, and how many were sent a form?
The book runs all twenty stages in order; the address here is chapter 11.
Chapter 12
Tool: Codex · HubSpot MCP · Follow Up Boss MCP.
Round robin is bought. Dropping is not. Every tier of the CRM you pay for hands the next enquiry to the next agent. Then it stops watching. At a six-person brokerage the Saturday enquiry has an owner by Sunday, and no call from anyone.
Round-robin is on every tier of the CRM you already pay for. Follow Up Boss lists "Round robin lead distribution" and "Advanced lead distribution based on price/ZIP Code" on its cheapest plan, at $69 a user a month (https://www.followupboss.com/pricing). This chapter builds no routing. What none of the products does is take a lead back when the person it went to does nothing with it.
The deepest public build stops in the same place. InsulaCRM (https://github.com/InsulaCRM/InsulaCRM) runs a locked round-robin and, every minute, force-assigns any lead nobody claimed inside three minutes. Then it looks away. A lead handed to an agent who does nothing for three weeks is never taken back.
"I've lost a ton of money due to leads slipping through the cracks" Trevor Y., Realtor, https://www.capterra.com/p/151891/LionDesk/reviews/
A 2011 audit of 2,241 US companies named the cause: "rules for distributing sales leads among agents and partners based on geography and 'fairness.'" (https://hbr.org/2011/03/the-short-life-of-online-sales-leads). It did not study real estate, and one author sold response software; the sentence still describes the rota. Fairness is chosen because the alternative is an argument.
30 per cent Of the commission, taken by a US portal at closing, for routing an enquiry to an agent who claims it. Above a price line it is 35 per cent. That is the market price of this stage left unbuilt.
Source: ReadyConnect Concierge referral fee, reported by Clever Real Estate, read 14 September 2026
Realtor.com's ReadyConnect Concierge, formerly Opcity, phones the enquiry itself, alerts agents by text or push, and an agent clicks to claim it (https://support.therealbrokerage.com/hc/en-us/articles/5978777311767-What-is-ReadyConnect-Concierge-formerly-OpCity). The fee is 30 per cent of the commission at closing on sales under $150,000 and 35 per cent above (https://listwithclever.com/real-estate-blog/everything-you-need-to-know-about-opcitys-referral-fee/). A brokerage that cannot keep its own enquiries moving pays a third of the revenue on every deal, forever, to a portal that can.
Open Codex. Ask for the timer. It reads each enquiry with an owner and nothing done in N minutes, and moves it, reason on the record. N is a ruling you make once. A lead never sits unowned, and never sits owned and untouched.
Open Codex in the engine folder. The enquiry chapter 10 routed to a viewing sits on a contact, with
the owner the rota gave it. Connect the CRM's own server. HubSpot's remote
server reads and writes contacts and the calls, notes and tasks on them, and reads owners and
teams (https://developers.hubspot.com/ai-tools/mcp). Follow Up Boss publishes no server of its
own; the live community one, written by a broker in Austin, covers the whole API, ponds
included (https://github.com/mindwear-capitian/followupboss-mcp-server). Write window.md
once: N, the minutes an owned enquiry may sit with nothing logged; what counts as action; and
the order a lead moves in, the next name in the rota, then the shared pool, then you. Then say
what you want:
Every five minutes, read every contact routed to viewing that has an
owner. Find the newest call, note, message or task the owner logged on
it. Where nothing has been logged for longer than the minutes in
window.md, move the contact to the next person in window.md, note on
the record who had it, how long it sat and who has it now, and create
a task for the new owner. Where an enquiry has no owner, give it one
the same way. Never delete anything and never message the client.
Report each morning: received, touched inside the window, moved, and
moved twice.
What comes back is a script, a schedule and four counts, and on every moved lead a note that says why.
Three honest limits, which Codex will tell you about. The timer reads what was logged, so a call from a personal phone that was never written down reads as no action, and the lead moves from someone who was working it; chapter 16 stops the logging depending on typing. A HubSpot account with sensitive data turned on blocks the activities the server reads (https://developers.hubspot.com/changelog/remote-hubspot-mcp-server-is-now-generally-available), so a run that sees nothing says so. And the Follow Up Boss server is one person's project with full write access; it can delete, and the instruction says never.
The viewing. The next stage books the viewing and stops the ones where nobody turns up. It needs an owner who acted. The number to read: enquiries with no action after N minutes, beside the total received, and how many moved.
Chapter 13 books the viewing and recovers the ones where nobody turns up. It needs a lead whose owner has done something.
The number that proves this stage worked is enquiries with no action after N minutes, beside the total received, and the count moved. A timer that never moves anything is either perfect or not watching.
Who is right for this client. The rota says who is next. Sometimes the principal should overrule it, and that overruling is protected here. N is a ruling, made once. What happens to a name moved three times is a conversation.
The rota answers who is next. Who is right for this client is a different question, and the principal sometimes answers it against the rota. The build never chooses between two people who both would act.
N is set once, in window.md, by a person who knows the team. A name that keeps appearing in
the moved column is a management matter:
"If they didnt have an emergency reason for missing the appointment, I would reévaluate their employment with me. They are representing you (as the Broker), not only is it disrespetful but reflects poorly on your company." Jacklyn Van Hoef, Fortune International Realty, Miami FL, https://activerain.com/questions/show/37083/when-realtors-do-not-show-up-at-a-scheduled-showing-appointment--how-do-you-deal-with-it-
Nothing new to buy. CRM: the owner, a note on every moved lead saying why, and a task for the new owner. Rota: the round robin you already pay for stays. The build watches what it decided. Pool: the shared list an enquiry falls into when nobody in the rota acts, before it reaches you.
CRM gains a note on every moved lead and a task for its new owner; HubSpot here, or Follow Up Boss, Pipedrive or Zoho through their own servers. Rota is the product's round-robin, untouched. Pool is the pond on Follow Up Boss: where a lead goes when the rota runs out of names.
Every enquiry has an owner who acted, and every one that sat is counted and moved. Then the viewing can book itself.
Ask: Of the enquiries that landed on Saturday, who found out on Monday that nobody had called?
The book runs all twenty stages in order; the address here is chapter 12.
Chapter 13
Tool: Claude Code · Calendly MCP · Google Calendar MCP · WhatsApp Cloud API MCP.
The viewing is booked. Saturday is not. The scheduler sends the invite and the reminder. The confirmation goes by hand, from a personal phone, the night before. For a six-person brokerage the one who never came is a blank in the diary, and the blank leads nowhere.
Booking is solved, and cheap. Calendly, cal.com or the calendar you already pay for takes the viewing, sends the invite and the reminder, for nothing to fifteen dollars a month. What no scheduler does is confirm the viewing on the channel the client answers on, notice when nobody confirms, and turn the one who never came into a follow-up with a reason. That half is done by hand, and every agent invents the same method:
"I usually text or call to confirm a couple hours prior. If they still miss the appointment -- I will call them and make a point to say they should have called, text, or emailed to let us know. Then they go on a watch list for the future!" Kim Johnson, Signature Realty Inc., Coral Springs, https://activerain.com/questions/show/37083/when-realtors-do-not-show-up-at-a-scheduled-showing-appointment--how-do-you-deal-with-it-
The text goes from a personal phone for a reason chapter 8 read on Meta's pages: a confirmation the day after the booking is outside the 24-hour window the client opened, so on the business number it is a paid template. The public code has the same gap: the one open CRM with a no-show status sends the client nothing, and nothing reads the status back.
$250 What one Florida broker bills the other side for a viewing nobody attended. Her count, never a market rate.
Source: Annette Lawrence, ReMax Realtec Group, on ActiveRain, read 14 September 2026
"First they go on THE LIST. (I'll get my time back) Next I send their broker a $250 Non-Fullfillment bill." Annette Lawrence, ReMax Realtec Group, Palm Harbor, https://activerain.com/questions/show/37083/when-realtors-do-not-show-up-at-a-scheduled-showing-appointment--how-do-you-deal-with-it-
One agent's answer, printed as hers. There is no published no-show rate for property viewings; every percentage found came from a company selling the booking, so none is printed. The seller's loss, in her words:
"The seller has rescheled their evening, arranged for someone to keep the dogs, made a reservation at the resturant, they tweeked up the house, lit the candles turned on the pool fountain, baked the cookies....and when that agent does not show up, who do they think the owner puts in the crosshairs?" Annette Lawrence, https://activerain.com/questions/show/37083/when-realtors-do-not-show-up-at-a-scheduled-showing-appointment--how-do-you-deal-with-it-
Open Claude Code. Ask for the evening. Calendly and the calendar are read at six. The confirmation goes out as a utility template, on the number they answered. Silence is a call before Saturday. The no-show is read from Calendly and becomes a follow-up with a reason.
Open Claude Code in the engine folder, beside chapter 8's Cloud API server and chapter 11's webhook receiver. Connect Calendly through its own hosted server at mcp.calendly.com, which carries a no-shows group beside scheduled events and invitees (https://developer.calendly.com/docs/mcp/calendly-mcp-server), and the diary through taylorwilsdon/google_workspace_mcp, with chapter 9's fifteen minutes for the OAuth setup. Submit a utility template the day before, address and time as variables, and wait for APPROVED. Then say what you want:
Every evening at six, read tomorrow's viewings from Calendly and the
calendar, and tell me the count before you do anything. Confirm each on
the channel the person last answered on, from the business number only.
On WhatsApp, a plain message if their window is open; if it has closed,
the approved utility template viewing_confirm. By nine at night, list
every viewing with no reply so I can call. After each viewing time,
read Calendly for invitees marked no-show and write a follow-up task in
the CRM for the morning: address, time, whether they confirmed, and
what happened. Report three counts each morning: confirmed, unanswered,
did not come.
What comes back is a script, two schedules and three counts.
Why the template. "When the window closes, you can only send pre-approved template messages" (https://developers.facebook.com/docs/whatsapp/cloud-api/guides/send-messages). A confirmation of something the client asked for is Meta's utility category. "Utility templates delivered within an open customer service window are free" (https://developers.facebook.com/documentation/business-messaging/whatsapp/pricing); outside it, Meta charges per message delivered, at a rate on its own card.
Why the no-show comes from Calendly. No calendar knows who stood at the door. You mark the no-show on your phone, and the run reads that mark back into a task with the facts beside it.
Three honest limits, which Claude Code will tell you about. A client that asks you to paste a client id and secret "does not support DCR and will not work with Calendly MCP" (same page). A viewing typed into the calendar by hand has no Calendly record, so its no-show is a line you add. And cal.com's official server is unpushed since May 2025; a cal.com house calls its API v2 instead.
The follow-up. A viewing that happened feeds the next chapter, in the words the client used. One that did not feeds a call. The number to read: confirmations answered over viewings booked, and no-shows split by whether they had answered.
The next chapter matches what the client said at the viewing to your books, so it needs to know which viewings happened. A no-show with a reason attached is still a client.
The number that proves this stage worked is confirmations answered over viewings booked, with the no-shows split by whether they had answered. Nobody publishes that split.
The call after the no-show. Whether they were rude or had a bad week is a judgement, made on the phone, never by a rule. Whether they view again, and what the seller is told, is yours.
A person makes the call:
"just can't do much! However, keep calling and next time, check twice before you leave for the appointment." Praful Thakkar, LAER Realty Partners, Burlington, https://activerain.com/questions/show/37083/when-realtors-do-not-show-up-at-a-scheduled-showing-appointment--how-do-you-deal-with-it-
Whether it was a life event or a lack of courtesy is decided on the phone, and the watch list is yours to keep. So is the seller: the tool never tells a seller who did not come.
Nothing new to buy. Scheduler: Calendly or the calendar, booking as before, read each evening. Number: the business number from chapter eight, sending one utility template per viewing. CRM: a follow-up task per no-show, with the facts beside it.
Scheduler is Calendly through its own server, or Google Calendar through the community one. Number is chapter 8's business number, with one approved utility template. CRM is HubSpot, Pipedrive or Zoho through their own servers, or Follow Up Boss.
Every viewing confirmed on the channel they answer, and every no-show a call with a reason. Then the follow-up happens by itself.
Ask: Of last Saturday's viewings, how many did you confirm the night before, and how many did nobody come to?
The book runs all twenty stages in order; the address here is chapter 13.
Chapter 14
Tool: Codex · Memory MCP · Excel MCP · Airtable MCP.
Match on fields, then send twenty. In the UK the register has a name and a product. It matches price to price and beds to beds. For a six-person brokerage the thing the client actually said on the phone lives in one head, and matches nothing.
In the UK this stage has a name, the applicant register, and every agency suite runs one: Expert Agent, Alto. Neither publishes a price. The portal runs the same match for free: Rightmove sends alerts on matching criteria straight to the buyer, with no agent in the loop (https://faq.rightmove.co.uk/support/solutions/articles/7000048758-how-to-register-for-property-alerts). What nothing matches on is what the client said.
Expert Agent's own manual shows what automatic costs: three clicks, then a dialog with four decisions by hand, every run, before a box says how many matched. Then the vendor writes the sentence against its own interest:
"If an Applicant has a price range of £0 to £0 it will match out to ALL properties." Expert Agent manual, https://learningcentre.expertagent.co.uk/ea-manual/matching/match-processor/matching-a-property
An applicant nobody finished matches everything, and you either send them the whole book or stop trusting the list. The register rots from incompleteness.
The form's requirement is also the wrong object. A broker in Utah:
"We arrived at one, and they said 'oh no, I don't like this one'… We walked in, and they fell in love. I inquired what they didn't like about the outside and they said they wanted a concrete driveway for the RV parking (not dirt) AN EASY FIX!!" Paula Smith, associate broker, St George UT, https://activerain.com/blogsview/265739/if-you-make-a-showing-appointment---actually-show----
A concrete driveway is a field on no form. A perfect filter would have missed the house.
Four decisions, every run The choices the vendor manual asks of you each time the match processor opens, after three clicks to reach it. Nobody has timed the twenty sent and none liked, so this book prints no hour.
Source: Expert Agent manual, read 14 September 2026
The manual counts decisions, never minutes. The second cost is the list you stop reading. Once one unfinished applicant has matched everything, the match list reads as noise and the sending goes back to memory: you send what you recall, and the client hears from the portal first.
Open Codex. Ask for the shortlist. It reads the register you keep and what each client said, and writes a shortlist with one sentence per match. A match it cannot explain in one sentence is dropped. You read the list before anyone is told.
Open Codex in the engine folder. The register is the spreadsheet you already keep, one row per property. Connect it: for Excel, the community Softeria/ms-365-mcp-server (https://github.com/Softeria/ms-365-mcp-server); for Airtable, Airtable's own hosted server or domdomegg/airtable-mcp-server, which returns a hundred rows unless asked for more.
What the client said sits in two places: the three fields chapter 10 wrote, and the thread chapter 11 stored on the contact. Chapter 10 also recorded it in the Memory server from the protocol's reference repository (https://github.com/modelcontextprotocol/servers): one entity per client, each thing they said an observation. The sentence that fits no field, the driveway, goes there too. Then say what you want:
Read the register, every row, and tell me the total first.
For each client whose route is viewing or follow-up, read their three
fields, every observation on them in Memory, and the whole thread.
Shortlist at most three properties per client. For each, write one
sentence saying why this one for this person, in their words, and one
sentence saying what is wrong with it. Where a property misses a field
but answers something they said, keep it and say which sentence. Where
you cannot write the why in one sentence, drop it. Send nothing. Write
the shortlist in a sheet beside the register and report three counts:
clients with a shortlist, clients with nothing this week, matches
dropped as unexplained.
What comes back is the shortlist and three counts, waiting for you.
The one sentence is the whole stage. The deepest public build scores +25 for price, +25 for type, +20 for the zip code and +15 for the state, and tells the agent, never the client (https://github.com/InsulaCRM/InsulaCRM). Membership is exact, so a buyer who wants a three-bed at £500,000 scores zero against a £505,000 three-bed one postcode over. A model reading "somewhere for the RV" beside a row with a wide drive can say why.
Two honest limits, which Codex will tell you about. A model matching on prose can be too kind; that is why the unexplained count is reported and why a shortlist stops at three. And a call nobody wrote down matches nothing.
Telling them. The next stage sends each client their shortlist with its reason, on the channel they answered on. The number to read: properties the client replied about, beside the count sent, and the clients told nothing.
The shortlist you approved goes to the client with its sentence, on the channel chapter 7 picked; on WhatsApp, inside the window or by template, as chapter 8 built it. A client with nothing suitable this week is told that, which is the message the portal alert never sends.
The number that proves this stage worked: properties the client replied about, beside the count sent, and clients told nothing this week.
The why, and the no. A person reads the shortlist and the flaw before the client does, and deletes the match that reads as a stretch. Telling a client that nothing suits them this month is a sentence a person sends. No alert ever will.
The tool cannot see the house from the kerb:
"Once in a while, I will have a buyer not want to see the inside of a house when we drive up. I always tell them that you can't always tell a book by it's cover" Dotti Driver, Sky Realty, Austin TX, https://activerain.com/blogsview/162905/no-show-showings-------no-call-either---argh-
So a person reads every why and deletes the stretches, and sends the message that nothing suits them this month. The sentence that fits no field reaches Memory only if a person writes it down.
Nothing new to buy. Register: the spreadsheet you keep, read by the tool instead of filtered by hand. Memory: what each client said, one entity each, the odd sentence included. CRM: the shortlist and its reason on the client, dated.
Register is the spreadsheet you already keep; it gains a shortlist sheet beside it. Memory holds what each client said, so the next run reads only what is new. CRM gains the shortlist and its reason on the client, dated.
Three properties per client, each with a why and a flaw, read by you first. Then telling them can happen by itself.
Ask: Of the properties you sent last week, how many carried a sentence saying why this one, for this person?
The book runs all twenty stages in order; the address here is chapter 14.
Chapter 15
Tool: Claude Code · Firecrawl MCP · Gmail MCP · HubSpot MCP.
The database defeats the person. The drip is bought and cheap. What is not bought is knowing who is due, and why, before they open a portal. For a six-person brokerage the past clients sit in a CRM nobody opens. The touch lives in one head.
Drip campaigns are cheap and everywhere. Follow Up Boss includes sequences from $69 a user a month (https://www.followupboss.com/pricing); Wise Agent is $49 a month. A CRM at that price stores the past-client list and sends the anniversary, so the referral drip is bought too. What none of them knows is when one person is worth a real message, or which past client would say yes if asked.
A broker of 33 years:
"Like everyone else, it is a struggle for me to personally stay in touch with past clients" Dave Rosenmarkle, Highland Realty, Fairfax VA, https://activerain.com/blogsview/11433/client-follow-up-systems--what-really-works-
A 39-year veteran, on what follows closing:
"never had any.... they never forgot me... there were too many to keep in touch with....didn't have time nor did I have the desire" Barbara Todaro, Keller Williams Elite, Franklin MA, https://activerain.com/questions/show/56518/what-is-your-post-closing-client-follow-up-program-
Neither says they do not want to stay in touch. They say they cannot keep up with who.
One and a half attempts How many times the trade calls a lead back after first contact, measured across 384 brokers. By email, two. On WhatsApp every touch after the window closes is a paid template. On email it is free.
Source: WAV Group with the Weichert Lead Network, 2014, read 14 September 2026
The one measured number is from 2014: 1.5 call-back attempts and 2.07 email attempts, secret-shopped across 384 brokers (https://www.wavgroup.com/2014/01/13/agent-responsiveness-study-reveals-critical-flaws-in-real-estate-lead-response/).
The cost that decides the design is Meta's. "When the window closes, you can only send pre-approved template messages" (https://developers.facebook.com/docs/whatsapp/cloud-api/guides/send-messages). "All non-template messages are free" (https://developers.facebook.com/docs/whatsapp/pricing). A touch after nine quiet weeks is a marketing template, with prior opt-in. And it is capped: "The per-user marketing limit adapts automatically over time based on a person's recent engagement levels" (https://developers.facebook.com/documentation/business-messaging/whatsapp/templates/marketing-templates/per-user-limits), shared across every business that messages them, failing with error 131049 rather than queueing. A reply opens a 24-hour window, and marketing sent inside it does not count toward the limit. So on WhatsApp the objective inverts to a reply, because a reply turns a paid marketing template into free service messaging.
Open Claude Code. Ask for the signal. Firecrawl watches the pages the client named. A change becomes a task on the record, with a reason and a draft. Email goes freely. A WhatsApp touch goes only when it can earn a reply, which opens the free window.
Open Claude Code in the engine folder. Connect three servers. HubSpot's remote server reads
and writes contacts, notes and tasks (https://developers.hubspot.com/ai-tools/mcp).
Firecrawl's official server has monitor tools that watch pages for change
(https://github.com/firecrawl/firecrawl-mcp-server). Gmail comes through the community Google
Workspace server (https://github.com/taylorwilsdon/google_workspace_mcp). Write signals.md
once: per contact, the pages worth watching and why, such as the building they asked about
or the planning register for their street, and the month their lease ends. Then say:
Read every follow-up contact and signals.md. Set a Firecrawl monitor
on each page and check daily. When a page changes in a way that
touches what the person said, or a date they named is thirty days out,
create a task on the contact: the signal, the message it traces to,
and one draft touch in my words that asks something they want to
answer. Send nothing on WhatsApp. On email, send the draft where I
have marked the contact send freely; otherwise leave the task for me.
Once a month, name the three past clients whose deal and every touch
since say they would say yes to an introduction, and why.
Report each Monday: signals, tasks made, tasks answered, contacts
touched zero times this year.
What comes back is a script, the monitors and a task queue on the record. A WhatsApp touch is sent by you, from chapter 8's business number, as an approved marketing template with the opt-in on file, written to be answered; never from a personal session, whose terms forbid applications that "interact with our Business Services without our prior written consent" (https://www.whatsapp.com/legal/business-terms). The draft stays on the task; the deepest open CRM drafts one for idle leads and throws it away (https://github.com/InsulaCRM/InsulaCRM).
Two honest limits, which Claude Code will tell you about. A monitor sees that a page changed; a price drop and a photo swap look the same until a person reads it. Firecrawl's hosted endpoint is free without a key, with rate limits; past them you pay.
The call that comes back. The next stage keeps the record true without typing. Every touch made here already sits on it. The number to read: contacts touched four times in twelve months, beside those touched zero times.
Chapter 16 keeps the CRM true without typing; every task and send here already sits on the contact. Chapter 20 reads the Monday number.
The number that proves this stage worked is people contacted four times in twelve months, beside the total, with the zero count named; never a rate alone.
The message, and the ask. The machine names who is due and why. A person writes the touch, or decides this client is one to leave alone. A person asks for the introduction, of the past client the record says would say yes.
The objection is that the eighteen-month client is exactly the relationship a machine must not touch. It does not: it names who is due and why, and drafts; a person sends, or does not. Barbara Todaro's "they never forgot me" is a strategy, and nothing here says every brokerage needs 450 nurtured contacts.
The referral ask is the one movement no product runs: nothing found ranks a past client by how likely they are to introduce you. The build names three, with the reason. A person makes the ask.
Nothing new to buy. CRM: a task per signal, with its reason and a draft. Mailbox: the free channel; a touch goes out whenever the record says so. WhatsApp: a paid template with opt-in, sent by a person, written to be answered. Watcher: Firecrawl monitors on the pages each client named.
CRM gains a task per signal with its draft; HubSpot here, or Pipedrive or Zoho through their own servers. Mailbox is Gmail, or Microsoft 365 through its own server. WhatsApp is chapter 8's business number. Watcher is Firecrawl, free with rate limits.
Every client who buys in two years has a watched signal on the record, and a touch they will answer. Then the call comes to you, not the portal.
Ask: Of the people you spoke to last year who were not ready, how many have heard from you since for a reason they would recognise?
The book runs all twenty stages in order; the address here is chapter 15.
Chapter 16
Tool: Codex · HubSpot MCP · Google Calendar MCP · Gmail MCP.
The best CRM is the one you use. Two agents in one thread said it, unprompted. Nobody says it about a spreadsheet. It is an admission. For a six-person brokerage the record is whatever six people typed after the call, which is mostly nothing.
Nothing runnable does this stage, so there is no product to concede. Nine public repositories were opened at source, and every logger in every one is a form. The best says so in its own code: "One-tap call logging is the highest-frequency write in the product, so the POST body is deliberately small" (https://github.com/Aaryan-336/PROPERTY_CRM), and a person still opens the app after the call and taps. Not one repository has any telephony at all.
So the record is typed, which mostly means it is not:
"I use Follow Up Boss - there's so many models of this but the best CRM is the one you use." Lien Vuong, agent, Boston, https://www.biggerpockets.com/forums/21/topics/845215-real-estate-agent-crm
"I use Mojo Sells, but as stated here, the best CRM is the one you use!" Steve Bracero, agent, Westboro, same URL
The sentence exists only for a category where leaving it unused is normal. The people doing the typing name the typing:
"Having to keep up with the data input from each client is a bit tough" Gary P., principal broker, https://www.capterra.com/p/152143/Top-Producer-CRM/reviews/?page=3
Zero, on the record No agent has named the hours the typing takes, so this book prints none. The cost is paid in absence. A contact with nothing written on it is a call the next person starts blind.
Source: no hours figure exists in any fetchable source; Capterra reviews of Follow Up Boss, Top Producer and LionDesk, read 14 September 2026
A buyer answered on Tuesday from a personal phone is, on the record, a buyer nobody answered; chapter 12's timer moves that lead away from the person working it, and chapter 20 reports on Monday a week quieter than the week was.
"I will sometimes get communication from a client and it won't alert me." Haley J., real estate agent, https://www.capterra.com/p/130020/Follow-Up-Boss/reviews/
Open Codex. Ask for the witnesses. The tool that saw the event writes it: the calendar the meeting, the mailbox the email, the webhook the message. Nothing is summarised and nothing is invented. A contact silent for thirty days is a count, never a nag.
Open Codex in the engine folder. Connect the CRM's own server: HubSpot's, at mcp.hubspot.com,
writes "calls, emails, meetings, notes, and tasks" on a contact
(https://developers.hubspot.com/ai-tools/mcp). Connect the calendar and the mailbox through
taylorwilsdon/google_workspace_mcp (https://github.com/taylorwilsdon/google_workspace_mcp).
The WhatsApp thread is already in chapter 8's webhook store. Write witnesses.md once: which
calendar, which mailbox, which number, and how a contact is matched, phone first, then email.
Then say what you want:
Every fifteen minutes, read the calendar, the mailbox, the message store
from chapter 8 and the call log. For each event whose other party
matches a contact in witnesses.md, write it on that contact once: a
meeting with its time, place and who came; an email with its subject
and body; a message with its text and direction; a call with its time
and length. Use the event id so nothing is written twice. Never invent
an event, never summarise one, never write on a contact you cannot
match; list those in nomatch.md. Each Monday, count every contact
with no event in thirty days and print the count beside the total, with
their names.
What comes back is a script, a schedule, and two Monday numbers with names under them.
Three honest limits, which Codex will tell you about. Calls are the thin part: no public server
executes a call log (Twilio's hosted one "does not execute API calls on your behalf",
https://www.twilio.com/docs/ai/mcp), so a call is written by a script against the Voice REST
API of the number you rent, or the CRM's own calls endpoint; a call from a personal mobile
is seen by no API and written by nobody, and the Monday number shows it as silence. A HubSpot
account with sensitive data turned on blocks the activity objects
(https://developers.hubspot.com/changelog/remote-hubspot-mcp-server-is-now-generally-available).
And Salesforce is the exception: its vendor server has one data tool, run_soql_query, and no
record write (https://github.com/salesforcecli/mcp), so there the writing goes by script.
The Monday number. The last stage reads which stage leaks. It can only read events that were written, with what was said. The number to read: interactions in thirty days with a record, beside the total from the phone and WhatsApp.
Chapter 20 reads the Monday number and says which stage is leaking. It can only count events that were written, and the next conversation is prepared from what was kept, which is why the build writes the email body and never a line saying an email happened.
The number that proves this stage worked is client interactions in the last thirty days with a record attached, beside the total from the phone and the message store. A CRM measured against itself reads complete every time.
What was said in the room. A record shows a budget was mentioned. Only the person on the call heard whether it was said with hesitation. The note only a person can write, and the decision to leave something delicate unwritten.
The machine writes what happened. A person writes what it meant. A budget on the timeline is a number; that it was offered reluctantly is a note only the person in the room can write. Keeping a divorce off the record is a judgement, made each time.
What a person does write goes into fields, the nine from chapter 10 and the outcome from chapter 13, never a transcript. A transcript on a timeline is one more thing nobody reads.
Nothing new to buy. CRM: the vendor server writes calls, emails, meetings and notes on the contact. Salesforce only reads. Calendar: every viewing on the diary lands on the contact as a meeting. Mailbox: every email to or from a contact, subject and body. Number: the webhook store from chapter eight, and the call log of a rented line.
CRM is HubSpot through its own server, or Pipedrive through mcp.pipedrive.ai
(https://www.pipedrive.com/en/features/mcp-server). Follow Up Boss has /calls,
/textMessages and /notes on its API (https://docs.followupboss.com/llms.txt) and one live
community server, by a broker in Austin, with "full read AND write access to your Follow Up
Boss account" (https://github.com/mindwear-capitian/followupboss-mcp-server): one person's
project, and it can delete. Calendar and Mailbox are one community server. Number
is chapter 8's business number, plus any rented line.
Every meeting, email, message and call on the contact, written by the tool that saw it, and a count of who has gone quiet. Nobody typed a word.
Ask: Of the conversations your team had last week, how many are on the record this morning, and who counted?
The book runs all twenty stages in order; the address here is chapter 16.
Chapter 17
Tool: Claude Code · Notion MCP · Google Drive MCP · Playwright MCP.
The pitch is retyped from memory. Commercial brokers have Buildout, and the offering memorandum comes out of a template. This chapter is for everyone else. For a six-person brokerage the pitch is the last deck with the address changed, and one fact wrong.
Commercial brokers have this stage covered. Buildout produces offering memorandums and proposals from templates. Its price is not printed because Buildout does not print it: its pricing page returned nothing on 14 September 2026, and aggregators disagree by more than five times. This chapter is for the residential and advisory reader, where nothing runnable exists: the most-starred open comparables project has 38 stars and was last pushed in June 2019 (https://github.com/jayshah5696/AutomaticValuationModel).
The trade has a job title for the hand:
"Gather all listing information including property photos, pre-listing materials, comparative market analysis with online property profiles, and MLS research" Wizehire, listing coordinator job description, https://wizehire.com/listing-coordinator-job-description
The trade calls this the "front half" of a deal, "getting the home on the market correctly and beautifully", against the "back half", "managing the contract-to-close paperwork". No single page owns that line; it is printed as how the trade talks.
Where there is no coordinator, the principal is one. The tenure chapter 3 wrote in a column is typed again from memory; what chapter 11 stored is remembered wrong. The pitch reaches the room a fact light.
$33,000 a year What the US trade pays the listing coordinator, the person whose duty list names the comparative market analysis. National average. No hours-per-pitch figure survives a check, so this book prints none.
Source: Wizehire listing coordinator job description, read 14 September 2026
"$33,000 (National Average)" is the same page, $6,000 below what it prints for the transaction coordinator, "$39,000 (National Average)". The line about how long a market analysis takes traces to a vendor blog, so it is not printed.
The cost that is never a salary is the retyping. Every fact in the pitch is already in the record; typed a second time, one changes, and the client notices which.
Open Claude Code. Ask for the pitch. The facts come from the record written since chapter three: the reason, the three fields, the thread, the match. The page is written in Notion or Docs, in your voice. The browser prints the PDF. The price stays yours.
Open Claude Code in the engine folder. Everything the pitch needs is already in the record: the Owners sheet from chapter 2; the reason from chapter 3; the voice folder from chapter 6; the three fields and the thread from chapters 10 and 11; the shortlist from chapter 14; the calls and meetings from chapter 16. None of it is retyped.
Connect three servers. The CRM's own server supplies the facts: HubSpot's reads contacts,
deals and the notes and calls on them (https://developers.hubspot.com/ai-tools/mcp).
The page is written in Notion through its own remote server
(https://developers.notion.com/docs/mcp), or in Docs and Drive through
taylorwilsdon/google_workspace_mcp. Playwright MCP prints the page
(https://github.com/microsoft/playwright-mcp). Write pitch.md once: your sections, in
order, and what each may draw from. Then say what you want:
Read the seller I name: the three fields, the reason on their row in
the Owners sheet, the whole thread, and every event written on them.
Build the pitch from pitch.md from facts that carry a source in the
record; where a section needs one it does not hold, write not on
record and leave it to me. For comparables, read my closed
deals in the register and the Owners sheet rows on the same streets,
with page and date. Open no portal. Write it as a page in Notion under
Pitches, in the voice folder's voice, a source under every fact, the
price section empty. Print it to PDF with the browser and save it in
Drive beside the contact. Report three counts: facts with a source,
sections left to me, comparables found.
What comes back is a page, a PDF beside the contact, three counts, and an empty price section.
Why the browser prints it. Playwright MCP carries browser_pdf_save, so the pitch is
written as HTML and printed. The three PDF servers this book found have four stars between
them, and one sends your document to a hosted service.
Why no portal is opened. The comparables are your own closed deals and chapter 2's public record, with its page and date. A view assembled from what you hold is a rule about the build, never advice about the law.
Three honest limits, which Claude Code will tell you about. A comparable from your own books exists only if the deal was written in the register. Where the public record publishes no price paid, the section reads not on record. And the pitch sounds like the voice folder, so twenty proposals you regret produce one more.
The negotiation. A pitch built from the record goes into the room with a source under every fact, and the price still yours. The number to read: hours from instruction to the document in their hands, and pitches sent the same working day.
The next chapter keeps an agreed deal moving to signature, from the facts the client was shown: a seller shown their own tenure and their own street's record does not argue them at the counter.
The number that proves it worked is hours from instruction to document in hand. No win rate for pitches is printed, because none is published.
The price, and the room. The tool assembles the comparables. The price opinion and the argument for it are yours, and carry your name. What a seller hears about their own home is said by a person, across a table.
The chain gathers; a person prices. The coordinator's duty list stops at "Gather", and so does the build: the comparables arrive with their pages and dates; the number the seller is told, and the case for it, is the consultant's, who defends it across the table. The empty section is empty on purpose, and so is the room: the PDF is what stays behind when the person leaves.
Nothing new to buy. CRM: the facts, read through its own server, never typed twice. Notion: or Docs, where the pitch is written and kept, one page per seller. Browser: Playwright, printing the page to PDF, no PDF product bought.
CRM is HubSpot, Pipedrive or Zoho through their own servers. Notion is its own remote server, or Docs and Drive through the community server. Browser is Playwright MCP, run headless.
Every pitch built from the record you already keep, a source under every fact, the price yours. Then the negotiation starts ahead.
Ask: Of the pitches you sent last month, how many carried a fact you had already written down once and typed again?
The book runs all twenty stages in order; the address here is chapter 17.
Chapter 18
Tool: Codex · Docusign MCP · PandaDoc MCP · HubSpot MCP.
Someone is paid to chase this by hand. The UK calls the job Sales Progressor. The US calls it Transaction Coordinator. Both liaise, update, resolve and record. For a six-person brokerage there is no such hire, so the chase is the principal, on evenings, from memory.
A product does this stage, coupled to a UK agency suite. Street.co.uk names "Offers" and
"Sales Progression" as surfaces, Reapit sells the same chain, and neither prints a price;
both route /pricing to a demo form, read 14 September 2026. Nothing else does it, and
no public repository models an offer, a counter or a chase.
So the trade hires a person. The advert is the method:
"Sales Progression: First and foremost, you will oversee the entire sales process by liaising effectively with buyers, sellers, solicitors, and mortgage brokers to ensure smooth transactions." ProFind Property Recruitment, Sales Progressor job advert, https://www.profindpropertyrecruitment.co.uk/jobs/job-title-sales-progressor-estate-agency/
The US seat, with the offer in it:
"Make sure the buyer's offer and counteroffers get approved by the seller to ensure a smooth real estate sales process" Wizehire, transaction coordinator job description, https://wizehire.com/real-estate-transaction-coordinator-job-description
Where there is no progressor, the principal is one.
£27,000 to £30,000 a year What a UK agency pays the person whose whole job is to chase agreed sales to completion. Basic, before commission. The US pays $39,000 for the same seat. Without the hire, the seat is your evenings.
Source: ProFind Property Recruitment and Wizehire job adverts, read 14 September 2026
"£27,000 to £30,000 PA" is ProFind's line; Wizehire prints "$39,000 (National Average)". No stall rate or days-to-signature average exists in any fetchable source, so none is printed. What the salary buys is a person who notices silence.
Open Codex. Ask for the chase. The stage is read from the signature server itself and written to the deal. A reminder is one tool call. Days since anything moved is the number, read per deal. It is printed, never sent.
Open Codex in the engine folder, where the deal chapter 17 pitched sits at agreed. Connect the signature vendor's own server. Docusign's, at mcp.docusign.com/mcp, is "now
available in Open Beta" and exposes the eSignature API
(https://developers.docusign.com/platform/mcp-server/). PandaDoc's, at
mcp.pandadoc.com/v1/mcp, tracks status and can "Send reminders for all contracts tagged
'Q4-2024' that haven't been signed yet"
(https://developers.pandadoc.com/docs/what-you-can-do-with-pandadoc-mcp). Then the CRM's
own: HubSpot's reads and writes deals (https://developers.hubspot.com/ai-tools/mcp). Write
deal.md once: the stages an agreed deal passes; who owes the next thing at each; the tag on your deal documents; and N, the days of silence you will tolerate.
Then say what you want:
Every morning, read every deal at agreed or beyond. Read the status of
its documents from the signature server, by the tag in deal.md, and
write the stage to the deal in the CRM, reason on the record. Find the
newest thing on the deal: a signature event, a note, a call, a message.
Print days since it, per deal, beside who owes the next
thing. Where a document has sat unsigned longer than N days, send the
signature server's own reminder once, and note it. Never send anything
else to anyone, never touch a price, never write a counter, never move
a deal to won or lost. Report: agreed, moved this week, silent past N
days, reminders sent.
What comes back is a script, a schedule and a table sorted by days.
Three honest limits, which Codex will tell you about. The Docusign server is a beta, and its page says so in capitals, provided "AS IS" and "AS AVAILABLE" without warranty. The lawyer and the lender answer on email, which no signature server sees, so a deal waiting on a lawyer reads as silent until chapter 16 writes the email on the deal. And the counter is a conversation the server never hears.
The file, and the next pair of hands. The next stage chases the documents the deal needs, from the stage this one wrote. A won deal carries every note and field since chapter three. Nobody asks the client twice.
Chapter 19 chases the compliance file from a stage read off the signature, never typed.
The won deal also feeds whoever serves the client next, and the reader never calls that a handoff. They call it the team. The cost is named from the receiving end:
"On one transaction I was asked to give the same information to both team members every time and it became a double workload for me." James Gordon, Sibcy Cline Realtors, Cincinnati, https://activerain.com/blogsview/42199/how-my-real-estate-team-works
The trade's fix is to hide the seller from the client:
"So if you have someone else answering your phone, the buyers will be more likely to be okay with working with a sub-agent." Chris Alston, Keller Williams Realty, Campbell, https://activerain.com/blogsview/2111411/you-are-adding-a-buyer-s-agent--why-do-they-always-seem-to-want-to-leave-the-team--10-ideas-to-help
The chain's fix: the won deal already carries everything written since chapter 3: the reason, the three fields, the thread, the viewing outcome, every event, the pitch, and the stage this chapter read. The number there is questions the delivery side had to ask that the seller could already answer; the target is zero.
The number that proves this stage worked is days from offer accepted to signature, and the milestones that moved without you sending the chase.
The negotiation, and the call when it stalls. The chase reads and reminds. Whether to push a party, and when, is a judgement made each time. The introduction to whoever serves them next, and the promise made in the sale, are yours.
The build chases the paperwork. It never makes the call. Nine days of silence is a number on a table; whether that is normal for this lawyer or a warning is read by the person who knows the lawyer. The reminder is the vendor's own, sent once. The second nudge is a phone call.
The handoff stays personal too: the introduction, and the promise made during the sale, are made by the person who made it.
Nothing new to buy. Signature: the vendor you already send through. Its own server reads status and sends the reminder. CRM: the deal gains a stage read from the signature, and a note for every reminder. Mailbox: the lawyer and the lender answer here, and chapter sixteen writes it on the deal.
Signature is whichever of Docusign and PandaDoc your agreements already go out through; PandaDoc's server carries the API's rate limits. CRM is HubSpot through its own server, or Follow Up Boss through the broker-written community server (https://github.com/mindwear-capitian/followupboss-mcp-server), which can delete. Mailbox is chapter 16's witness, untouched.
Every agreed deal has a stage read from the signature itself, a count of days since anything moved, and a file the next person reads first. Nothing dies in silence.
Ask: Of the deals you agreed this quarter, which one went quiet, and who noticed first, you or the client?
The book runs all twenty stages in order; the address here is chapter 18.
Chapter 19
Tool: Claude Code · Google Drive MCP · Airtable MCP · PandaDoc MCP.
The file closes when someone remembers. Storage is bought. Two paid products keep the documents. Neither says which is missing, from whom, or how late. For a six-person brokerage the list lives in one head, and the chase is a Friday afternoon of messages.
Storage is cheap. PropSpace lists Transaction Documents, in its own words a way to "Efficiently generate and manage invoices, receipts, and contracts", at AED 220 a user a month (https://www.propspace.com/pricing). Street.co.uk files compliance and renewals under property management, at a price it does not publish (https://www.street.co.uk/pricing). Both store. Neither is described as chasing.
The chase is a job. A US brokerage hires a Transaction Coordinator to:
"Enter client information into the client database system and submit appropriate documentation to the office broker for file compliance and keep track of transaction activity" Wizehire, Real Estate Transaction Coordinator job description, https://wizehire.com/real-estate-transaction-coordinator-job-description
That is the whole stage in one advert: a deal has a set of documents the file needs, each signed and dated, and somebody must know which are not there yet, who owes them, and for how long. This book does not say what belongs on that list. It differs by place and by deal, and it is yours. Without the hire, a document is chased when someone remembers it, with no record of the asking.
$39,000 a year The published national average for a US Transaction Coordinator, hired to know which document is missing. Without the hire, the list is your evenings.
Source: Wizehire, Real Estate Transaction Coordinator job description, national average salary, read 14 September 2026
No source gives hours per file, so this book prints none. The cost is a salary: $39,000, the national average Wizehire prints for the role (https://wizehire.com/real-estate-transaction-coordinator-job-description), paid in evenings where there is no hire. The other cost has no figure: a file audited by hand on completion day finds the missing item on the day it is hardest to get.
Open Claude Code. Ask for the list. The list is yours, once per deal type. The folder is read against it. Signatures come from the signature vendor. Who owes each missing item is a column. The chase is one reminder per item, with the days overdue.
Open Claude Code in the engine folder. Connect three servers. Google Drive comes through the community Google Workspace server (https://github.com/taylorwilsdon/google_workspace_mcp). Airtable's remote server reads and writes records (https://support.airtable.com/docs/using-the-airtable-mcp-server). PandaDoc's does status and signature tracking (https://developers.pandadoc.com/docs/what-you-can-do-with-pandadoc-mcp).
Write the base once. A required table: one row per deal type per document the file needs, named
in your words, with a column for who usually owes it: the client, the other side, or you. A deals table: one row per live deal, its folder and its dates. Then say:
Read both tables. For every live deal, list its Drive folder and match each file to a row on its deal type's
list by the name I gave it. Ask PandaDoc for the status of every
document sent on this deal; sent and unsigned is not present. Write
one row per deal per document: present, missing or unsigned, who owes
it, and days overdue against the deal's dates. For every missing or
unsigned item, draft one reminder in my words to the person who owes
it, naming the item and the days, and send it by email where I have
marked that person send freely; otherwise leave the draft on the row.
Never add a document that is not on my list. Each morning print one
line per deal: present of required, the oldest missing item, who owes
it, days overdue.
What comes back is a script, a schedule, one row per document per deal, and a morning line: the deal, nine of eleven, the oldest missing item, who owes it, six days.
Two honest limits, which Claude Code will tell you about. Present is not adequate: the chain matches a file name to a row; whether that file is the right version, signed by the right hand, is a person's read. And the reminder goes freely on email only. On WhatsApp it goes from chapter 8's business number, as a template once the window has closed, sent by you; never from a personal session, whose terms forbid applications that "interact with our Business Services without our prior written consent" (https://www.whatsapp.com/legal/business-terms).
The file, closed. The last stage reads which stage leaks on Monday. A file that closed itself is one Friday nobody spent chasing. The number to read: files complete on completion day with no audit, and the age of the oldest missing item.
Every email reminder lands on the contact through chapter 16: the record shows who was asked, for what, and when. Chapter 20 reads the Monday number.
The number that proves this stage worked is files complete on completion day without a manual audit, beside the total, and the age of the oldest outstanding document; never a rate alone.
What goes on the list. A person decides what a file needs, for their place and their deal. The machine never adds a line to it. A person makes the call when someone will not send, and reads whether what arrived is the right thing.
The objection is that a machine has no place near a compliance file. It is given none near the judgement. What the file needs is written by you, once per deal type; the machine reads against that list and never adds to it. Whether a document that arrived is the right one is a person's read, every time. The chain knows only present, absent, unsigned and overdue.
At six days a reminder is a draft. At twenty days, when the other side has gone quiet, it is a phone call, and the morning line only says the day has come.
Nothing new to buy. Folder: the deal folder you keep, listed each morning against your list. Checklist: one row per document per deal, with who owes it and the days overdue. Signatures: sent and unsigned, read from the vendor. Mailbox: the reminder goes out with the item and the days in it.
Folder is Google Drive through the community Workspace server, OneDrive through Softeria's Microsoft 365 server (https://github.com/Softeria/ms-365-mcp-server), or a folder on disk through the protocol's own Filesystem server. Checklist is Airtable, official or community (https://github.com/domdomegg/airtable-mcp-server), or a Google Sheet on the same Workspace server. Signatures is PandaDoc, or Docusign through its own server, "now available in Open Beta" in its own words (https://developers.docusign.com/platform/mcp-server/). Mailbox is Gmail, or Microsoft 365 Mail.
Every live deal on one line: what is missing, who owes it, and for how many days. Then the file closes itself.
Ask: For the deals live this week, can you say from your desk which document is still missing, and who owes it?
The book runs all twenty stages in order; the address here is chapter 19.
Chapter 20
Tool: Codex · Google Sheets MCP · HubSpot MCP · Chrome DevTools MCP.
You have four dashboards. You have no answer. Every product you pay for reports its own slice, and reports it well. This chapter concedes it first. For a six-person brokerage the join across them is a Monday with a spreadsheet.
Reporting is the most covered stage in this book. Follow Up Boss ships "Lead source reporting" and a "Team Leaderboard" (https://www.followupboss.com/pricing); PropSpace ships "Business Insights - Access critical performance data on leads and deals" (https://www.propspace.com/pricing). Nobody lacks charts.
Where they stop is the join. The portal reports the leads it sent you, on its own screen: Bayut
Profolio sorts them into "Email, SMS, Phone, WhatsApp and Chat leads", exportable to Excel
(https://www.bayut.com/agentportal/best-features-profolio-offers/), and Property Finder Leads
Insights filters the same by channel. The CRM reports what agents did and the back office
reports money. None holds portal spend next to the lead it bought, the deal it became and the commission
on it. Nor does public code: the one repository that reaches invoicing stores total and
grandTotal as String
(https://raw.githubusercontent.com/prolinkinfo/RealEstateCRM/main/server/model/schema/invoices.js),
and text does not forecast.
Zero, on the record No hours figure for this stage was verified anywhere, so this book prints none. What is paid is Tuesday, decided from a number nobody joined.
Source: no hours-per-task figure verified for any stage; vendor pricing pages, 14 September 2026
The commission half is the same. PropSpace at AED 220 a user a month is the one product found with a native split, "Deal Tracking - Accurately monitor completed deals and commissions earned by both the company and individual agents". If you have it, the split is calculated and your problem is reconciliation.
Open Codex. Ask for one table. Portal spend off the portal, leads and deals off the CRM, commission off your sheet. Every count carries its total. A number nobody wrote stays blank, never zero.
Open Codex in the engine folder. Connect a Sheets server, taylorwilsdon/google_workspace_mcp
(https://github.com/taylorwilsdon/google_workspace_mcp), and the CRM server, HubSpot at
mcp.hubspot.com (https://developers.hubspot.com/ai-tools/mcp). The portal publishes none, so the
browser reads it: chrome-devtools-mcp drives your own Chrome
(https://github.com/ChromeDevTools/chrome-devtools-mcp), where list_network_requests shows the
JSON behind the chart. Write monday.md once: the stage names, the sheet tab, the week that
counts. Then say what you want:
Every Monday at seven, read the portal lead dashboard and the spend
beside it in the open browser; from the CRM every deal that changed
stage in seven days; and the commission tab of the sheet. Write one
table: per stage the count in, the count out, and the total sitting
in it, so every count has its total beside it, plus a row for portal
spend and one for commission raised. Print each stage conversion
this week beside the same stage last week, and name the ONE stage
whose rate fell furthest. Where a value was never written print a
dash, never a zero, and list what you could not read.
What comes back is a script, a schedule and one table.
Three honest limits, which Codex will name. The portal read runs against your own logged-in Chrome, a tool that "exposes content of the browser instance to the MCP clients", so it runs on a screen you watch. A HubSpot account with sensitive data turned on blocks activity objects (https://developers.hubspot.com/changelog/remote-hubspot-mcp-server-is-now-generally-available), so that half reads short and says so. And the table is only as true as chapter 16 made the record.
There is no benchmark either: no conversion rate for this trade was found published anywhere, so your week compares only against your last.
Next week, and the asset you do not own. One stage fell. That is what changes on Tuesday, and the only thing that changes. Then the row nothing else holds: who was asked, and who never answered.
The table names one stage. That is Tuesday, and the rest is left alone, because a week in which four things changed teaches nothing. Then the half no product reaches: the reviews that win your next client sit on a portal you do not own, and a broker traced an appointment to them:
"It all began on a listing appointment for an $800,000 home when the sellers said they found me on Zillow. … It turns out they read some reviews about me on Zillow from past clients" Margaret Woda, Associate Broker, Long & Foster Real Estate, Crofton MD, https://activerain.com/blogsview/3624981/from-zillow-hater-to-zillow-profiteer
One deal, self-reported, and this book makes no rate of it. Her postscript names the gap: "I just need to be more conscientious about requesting reviews."
The platform says so itself. A managing broker published the email he got after a stranger who was never his client tried to rate him: "we are extending you a "Free Pass" and will not publish this review on your Zillow profile. Please note that this is a one-time courtesy" (J. Philip Faranda, Howard Hanna Rand Realty, Westchester NY, https://activerain.com/blogsview/2643070/zillow-agent-reviews--a-request-for-sanity). A Zillow employee replied in the thread: "The bigger issue is debate point of letting 'anyone with a computer' write a review" (Sara Bonert, same URL).
So the build owns the half it can: the Monday table gains a row per closed deal, who was asked, when, and whether a review appeared. No tool you pay for holds it.
The number that proves this stage worked is one screen where every count reconciles to the commission raised, plus past clients asked who never answered.
What changes on Tuesday. The table says which stage fell. Choosing what to do is a judgement, made weekly. And the ask itself: whether to ask this client for a review.
The table names the stage. What to do is yours, and writing it down each week is the discipline: a leak found and forgotten is a leak.
The ask is yours too, including not making it:
"And if it bothers you, don't do it. Your discomfort will be crystal clear to the person you're asking" Jennifer Allan-Hagedorn, Sell with Soul, https://activerain.com/blogsview/79075/what-s-the-best-way-to-ask-for-referrals--don-t--
The split agreement is a third. A machine flags where paid and agreed differ; varying one is a conversation.
Nothing new to buy. Portal: its own lead dashboard, read through your browser, spend beside it. CRM: the stages, the deals and what moved this week. Sheet: the commission tab you keep, and the review column you do not. Browser: the hands for a screen with no API behind it.
Portal is Bayut Profolio or Property Finder Leads Insights, whichever you advertise on; neither publishes a server, so the browser reads them. CRM is HubSpot, Pipedrive at mcp.pipedrive.ai, or Zoho Data Insights. Sheet is Google Sheets, or Excel through Softeria/ms-365-mcp-server (https://github.com/Softeria/ms-365-mcp-server). Browser is chrome-devtools-mcp, or playwright-mcp unattended.
One table on a Monday, every count carrying its total, one stage fallen. That stage is Tuesday.
Ask: Last Monday you read four dashboards. Which stage did they agree had leaked?
The book runs all twenty stages in order; the address here is chapter 20.
Appendix A
Every prompt in the book that runs on Claude Code, in chapter order. Each one also sits on the prompts page, where it can be copied.
Open Claude Code. Ask who called. It reads a year of proposals off disk, one row per job: who called, what asset, what for. It groups the rows and writes one sentence per group, with the count behind it. You keep one, and the list is built from it.
Open Claude Code in a new folder. Point the Filesystem MCP at your proposals and closing files, add the Memory MCP so what it learns survives the session, and say what you want:
Read every proposal and closing file from the last twelve months. Write
one row per file: the date, who called and what kind of entity, the
asset, the submarket, the trigger if the file shows one (never guess;
write unknown), what I was asked to do, whether it closed. Group the
rows by what I was asked to do and by who called, and write one
sentence per group: the entity, the asset, the submarket, the problem
that made them call. Save work.csv and target.md, keep each group in
memory, and report the row count behind every sentence.
Back come a few sentences, a count under each. Fourteen rows behind a sentence is
a problem people call you for; one row is a job you once took. Keep one, two at most, at the
top of target.md.
Two honest limits. The Filesystem MCP reads only the folders you allow it, so work that lives in an inbox or a WhatsApp thread never becomes a row. And the sentence is a first draft: who is behind an asset is invisible until the list exists, so chapter three sends rows back here. Define, then let the list correct you.
Open Claude Code. Ask for the reason. The tool that reads the row writes its score and its reason beside the row, dated, in two columns. A row nobody scored stays blank, never zero. A row archived stays archived, with its reason.
Open Claude Code in the engine folder. The owner list from the last chapter sits in a Google Sheet or an Airtable base. Connect it: for Sheets, the community server taylorwilsdon/google_workspace_mcp, with fifteen minutes budgeted for the Google Cloud OAuth setup; for Airtable, Airtable's own hosted server or the community domdomegg/airtable-mcp-server. Then say what you want:
Read the owners sheet, every row, and tell me the total before you start.
Skip any row whose status column reads archived; leave it and its reason
untouched. For each other row, read the recorded documents for the
parcel: the deed for the date it changed hands and the mortgage for its
maturity. Add columns beside the row: tenure in years, months to
maturity, the date you read them, and a one-line reason saying which
signal is live and where you read it. Score the row against
weights.md in its own column. Where you found no documents, leave the
score blank and write the reason as not read; never write zero. Report
three counts: rows read, rows with a live signal, rows you could not read.
What comes back is a script and three counts. Sort by score and the top twenty are the call list; the reason column is the opening line of each call.
Two rules are the whole stage. The score and the reason are written beside the row by the tool that read it, so a company archived last quarter stays archived, with its reason, through every later run. And a row nobody scored stays blank, because a zero on that row would read as a judgement, and nobody made one.
Two honest limits, which Claude Code will tell you about. The lease is rarely on record, so the signal the trade prizes most is written as not on record, a blank and never a no. The community Airtable server returns a hundred rows per call unless asked for more, which is why the instruction asks for the total first: four hundred rows read as a hundred is a list that lies quietly.
Open Claude Code. Ask for the basis. Every number carries where it came from and what permits the contact: published, given to you, or opted in. A number with no basis is held, never dialled. Beside each: its source, its date, the hours it may be contacted in.
Open Claude Code in the engine folder, beside people.csv from the last chapter and your CRM
contacts exported as crm-export.csv. Then say what you want:
Read people.csv. For every person, find a way to reach them, stopping at
the first rung that holds: a number or address the business itself
publishes; then one this person gave us, in crm-export.csv with its
date; then a WhatsApp opt-in we hold, with the date and their words.
Record the rung, its source and its date. Never take a number from a
bought database, a credit bureau product or a scraped list, and never
guess one. Add two blank columns for a person to fill: registry_checked
and hours. Write reach.csv with a source and a basis on every row,
holding.csv for the rest, and report four counts: published, given,
opted in, none.
What comes back is a script, a run and four counts. reach.csv carries a rung, a page or
message and a date on every row.
The hinge is the first rung. The FTC's own page says the US registry exempts "Most phone calls
to a business made with the intent to solicit sales from that business" (same URL as above). A
consultant calling a company about its premises is doing something different from an agent
calling a homeowner, and the company's published number is the widest honest lane this reader
has. The build does not decide what that sentence means for you. It writes the rung, dates
registry_checked when a person runs whatever check your market asks for, and flags any row
older than a month.
For WhatsApp the rung is Meta's. The Business Messaging Policy reads: "You may only contact people on WhatsApp if: (a) they have given you their mobile phone number; and (b) you have received opt-in permission from the recipient confirming that they wish to receive subsequent messages or calls from you" (https://whatsappbusiness.com/policy/). An opt-in someone else collected is never written as yours. The free lane, a client on your own phone, is named once, as the warning: the Business Terms forbid applications that "interact with our Business Services without our prior written consent" (https://www.whatsapp.com/legal/business-terms).
One honest limit, which Claude Code will tell you about: it cannot rule on whether a basis is enough in your market. A reader in Dubai meets different questions from a reader in Texas: consent before a message on a social platform, the hour of the day, naming yourself and your purpose at the start. The build answers none. It records the consent, the source and the hours, and chapter 6 opens every message with your name and why you are writing.
Open Claude Code. Ask for one inbox. Email replies arrive through Gmail, WhatsApp replies through a Cloud API webhook. Both land on one CRM record per owner. The personal-session lane is named once and never used. The terms you accepted forbid it.
Open Claude Code in the engine folder. Connect Gmail
through taylorwilsdon/google_workspace_mcp, the server that read your sheet, with fifteen
minutes for its Google OAuth setup. Connect the CRM through its own server, HubSpot's at
mcp.hubspot.com; Pipedrive and
Open Claude Code. Ask for the reply. Gmail reads the portal email; Playwright opens the portal inbox with no API. The reply goes back the way it came. It asks permission and the three questions. HubSpot gets the person and the note within the hour, whatever the hour.
Open Claude Code in the engine folder. Connect the mailbox the portal writes to: for Gmail,
the community server taylorwilsdon/google_workspace_mcp, with fifteen minutes budgeted for the
Google Cloud OAuth setup (the GongRzhe Gmail server the lists name is archived). For a
portal inbox with no feed, Microsoft's Playwright MCP, headless, with a saved login. For the
CRM, HubSpot's own remote server at mcp.hubspot.com. Write reply.md once: an acknowledgement
in your words, the consent line, and the next chapter's three questions, when, how much, and
whether the money is arranged. Then say what you want:
Every ten minutes, read the inbox for new portal enquiries, and read the
portal inbox in Playwright with the saved login. Tell me the total before
you do anything. Reply to each within the hour, on the channel it
arrived on: email by email, a portal message in the portal's own reply
box. Use reply.md, filled with the listing and their name, nothing else.
Never reply on WhatsApp. In HubSpot, create the contact if none matches
the email or phone, and add a note: the listing, what they wrote, when
it landed, when you replied. Leave the timeline, price range and
pre-approval fields blank until they answer; never fill them from a
guess. Report three counts each morning: landed, replied within the
hour, still waiting.
What comes back is a script, a schedule and three counts. At nine the morning starts with a list: who wrote overnight, what they were sent, who has answered. The reply is yours, written once; the tool fills in the name and the listing.
Why never WhatsApp. A portal email has not opened a WhatsApp window, so the first WhatsApp message to that person is a paid template, approved before the enquiry existed. That build is chapter 8.
Three honest limits, which Claude Code will tell you about. A saved portal login expires and a portal page changes shape, so a run that finds zero enquiries reports zero, never silence. HubSpot blocks notes if the account has sensitive data turned on. And two channels are not read here: a WhatsApp on a personal phone, since the book never reads WhatsApp Web, and a spoken referral.
Open Claude Code. Ask for the thread. The webhook receives it. Inside the window the model asks the three questions, one at a time, in your voice. When the three are answered, Calendly makes the link. A price, a hard question or anger goes to a person.
Open Claude Code in the engine folder. The number, the webhook and the message store are chapter 8's thin server; this chapter adds a reader. The shape, a webhook, a store and two send tools, is marco2901/whatsapp-mcp-server (https://github.com/marco2901/whatsapp-mcp-server): credit it, depend on nothing with zero stars.
Connect Calendly through its own hosted server at mcp.calendly.com, which carries a scheduling
links group (https://developer.calendly.com/docs/mcp/calendly-mcp-server). Write
conversation.md once: your first line, the permission line, chapter 10's three questions,
and the four things that end the machine's turn. Then say what you want:
When a message arrives on the webhook from a number with an open window,
answer inside the window and never after it closes. Use conversation.md:
my first line, then permission, then the three questions from chapter 10
one at a time, in my words, waiting for each answer. Write each answer on
the contact in their words, with its message. When all three are answered
and the route reads viewing, ask Calendly for a scheduling link and send
it. Stop and hand the thread to me the moment they ask a price, ask
something the listing does not answer, sound angry, or ask for a person:
tell them someone will reply. Log every message, both directions, on the
contact. Report three counts each morning: opened, links sent, handed to
a person.
What comes back is a script that watches the store, one thread per buyer, and three counts. The link books the viewing, and Calendly reports the booking to the contact.
Three honest limits, which Claude Code will tell you about. Calendly's server needs a client
that registers itself: "If your MCP client prompts you to paste in a client_id and
client_secret, it does not support DCR and will not work with Calendly MCP" (same page).
cal.com's official server is unpushed since May 2025; its link comes from its API v2. And a
yes to the money question, typed at ten at night, is the yes chapter 10 warned about.
Open Claude Code. Ask for the evening. Calendly and the calendar are read at six. The confirmation goes out as a utility template, on the number they answered. Silence is a call before Saturday. The no-show is read from Calendly and becomes a follow-up with a reason.
Open Claude Code in the engine folder, beside chapter 8's Cloud API server and chapter 11's webhook receiver. Connect Calendly through its own hosted server at mcp.calendly.com, which carries a no-shows group beside scheduled events and invitees (https://developer.calendly.com/docs/mcp/calendly-mcp-server), and the diary through taylorwilsdon/google_workspace_mcp, with chapter 9's fifteen minutes for the OAuth setup. Submit a utility template the day before, address and time as variables, and wait for APPROVED. Then say what you want:
Every evening at six, read tomorrow's viewings from Calendly and the
calendar, and tell me the count before you do anything. Confirm each on
the channel the person last answered on, from the business number only.
On WhatsApp, a plain message if their window is open; if it has closed,
the approved utility template viewing_confirm. By nine at night, list
every viewing with no reply so I can call. After each viewing time,
read Calendly for invitees marked no-show and write a follow-up task in
the CRM for the morning: address, time, whether they confirmed, and
what happened. Report three counts each morning: confirmed, unanswered,
did not come.
What comes back is a script, two schedules and three counts.
Why the template. "When the window closes, you can only send pre-approved template messages" (https://developers.facebook.com/docs/whatsapp/cloud-api/guides/send-messages). A confirmation of something the client asked for is Meta's utility category. "Utility templates delivered within an open customer service window are free" (https://developers.facebook.com/documentation/business-messaging/whatsapp/pricing); outside it, Meta charges per message delivered, at a rate on its own card.
Why the no-show comes from Calendly. No calendar knows who stood at the door. You mark the no-show on your phone, and the run reads that mark back into a task with the facts beside it.
Three honest limits, which Claude Code will tell you about. A client that asks you to paste a client id and secret "does not support DCR and will not work with Calendly MCP" (same page). A viewing typed into the calendar by hand has no Calendly record, so its no-show is a line you add. And cal.com's official server is unpushed since May 2025; a cal.com house calls its API v2 instead.
Open Claude Code. Ask for the signal. Firecrawl watches the pages the client named. A change becomes a task on the record, with a reason and a draft. Email goes freely. A WhatsApp touch goes only when it can earn a reply, which opens the free window.
Open Claude Code in the engine folder. Connect three servers. HubSpot's remote server reads
and writes contacts, notes and tasks (https://developers.hubspot.com/ai-tools/mcp).
Firecrawl's official server has monitor tools that watch pages for change
(https://github.com/firecrawl/firecrawl-mcp-server). Gmail comes through the community Google
Workspace server (https://github.com/taylorwilsdon/google_workspace_mcp). Write signals.md
once: per contact, the pages worth watching and why, such as the building they asked about
or the planning register for their street, and the month their lease ends. Then say:
Read every follow-up contact and signals.md. Set a Firecrawl monitor
on each page and check daily. When a page changes in a way that
touches what the person said, or a date they named is thirty days out,
create a task on the contact: the signal, the message it traces to,
and one draft touch in my words that asks something they want to
answer. Send nothing on WhatsApp. On email, send the draft where I
have marked the contact send freely; otherwise leave the task for me.
Once a month, name the three past clients whose deal and every touch
since say they would say yes to an introduction, and why.
Report each Monday: signals, tasks made, tasks answered, contacts
touched zero times this year.
What comes back is a script, the monitors and a task queue on the record. A WhatsApp touch is sent by you, from chapter 8's business number, as an approved marketing template with the opt-in on file, written to be answered; never from a personal session, whose terms forbid applications that "interact with our Business Services without our prior written consent" (https://www.whatsapp.com/legal/business-terms). The draft stays on the task; the deepest open CRM drafts one for idle leads and throws it away (https://github.com/InsulaCRM/InsulaCRM).
Two honest limits, which Claude Code will tell you about. A monitor sees that a page changed; a price drop and a photo swap look the same until a person reads it. Firecrawl's hosted endpoint is free without a key, with rate limits; past them you pay.
Open Claude Code. Ask for the pitch. The facts come from the record written since chapter three: the reason, the three fields, the thread, the match. The page is written in Notion or Docs, in your voice. The browser prints the PDF. The price stays yours.
Open Claude Code in the engine folder. Everything the pitch needs is already in the record: the Owners sheet from chapter 2; the reason from chapter 3; the voice folder from chapter 6; the three fields and the thread from chapters 10 and 11; the shortlist from chapter 14; the calls and meetings from chapter 16. None of it is retyped.
Connect three servers. The CRM's own server supplies the facts: HubSpot's reads contacts,
deals and the notes and calls on them (https://developers.hubspot.com/ai-tools/mcp).
The page is written in Notion through its own remote server
(https://developers.notion.com/docs/mcp), or in Docs and Drive through
taylorwilsdon/google_workspace_mcp. Playwright MCP prints the page
(https://github.com/microsoft/playwright-mcp). Write pitch.md once: your sections, in
order, and what each may draw from. Then say what you want:
Read the seller I name: the three fields, the reason on their row in
the Owners sheet, the whole thread, and every event written on them.
Build the pitch from pitch.md from facts that carry a source in the
record; where a section needs one it does not hold, write not on
record and leave it to me. For comparables, read my closed
deals in the register and the Owners sheet rows on the same streets,
with page and date. Open no portal. Write it as a page in Notion under
Pitches, in the voice folder's voice, a source under every fact, the
price section empty. Print it to PDF with the browser and save it in
Drive beside the contact. Report three counts: facts with a source,
sections left to me, comparables found.
What comes back is a page, a PDF beside the contact, three counts, and an empty price section.
Why the browser prints it. Playwright MCP carries browser_pdf_save, so the pitch is
written as HTML and printed. The three PDF servers this book found have four stars between
them, and one sends your document to a hosted service.
Why no portal is opened. The comparables are your own closed deals and chapter 2's public record, with its page and date. A view assembled from what you hold is a rule about the build, never advice about the law.
Three honest limits, which Claude Code will tell you about. A comparable from your own books exists only if the deal was written in the register. Where the public record publishes no price paid, the section reads not on record. And the pitch sounds like the voice folder, so twenty proposals you regret produce one more.
Open Claude Code. Ask for the list. The list is yours, once per deal type. The folder is read against it. Signatures come from the signature vendor. Who owes each missing item is a column. The chase is one reminder per item, with the days overdue.
Open Claude Code in the engine folder. Connect three servers. Google Drive comes through the community Google Workspace server (https://github.com/taylorwilsdon/google_workspace_mcp). Airtable's remote server reads and writes records (https://support.airtable.com/docs/using-the-airtable-mcp-server). PandaDoc's does status and signature tracking (https://developers.pandadoc.com/docs/what-you-can-do-with-pandadoc-mcp).
Write the base once. A required table: one row per deal type per document the file needs, named
in your words, with a column for who usually owes it: the client, the other side, or you. A deals table: one row per live deal, its folder and its dates. Then say:
Read both tables. For every live deal, list its Drive folder and match each file to a row on its deal type's
list by the name I gave it. Ask PandaDoc for the status of every
document sent on this deal; sent and unsigned is not present. Write
one row per deal per document: present, missing or unsigned, who owes
it, and days overdue against the deal's dates. For every missing or
unsigned item, draft one reminder in my words to the person who owes
it, naming the item and the days, and send it by email where I have
marked that person send freely; otherwise leave the draft on the row.
Never add a document that is not on my list. Each morning print one
line per deal: present of required, the oldest missing item, who owes
it, days overdue.
What comes back is a script, a schedule, one row per document per deal, and a morning line: the deal, nine of eleven, the oldest missing item, who owes it, six days.
Two honest limits, which Claude Code will tell you about. Present is not adequate: the chain matches a file name to a row; whether that file is the right version, signed by the right hand, is a person's read. And the reminder goes freely on email only. On WhatsApp it goes from chapter 8's business number, as a template once the window has closed, sent by you; never from a personal session, whose terms forbid applications that "interact with our Business Services without our prior written consent" (https://www.whatsapp.com/legal/business-terms).
Appendix B
Every prompt in the book that runs on Codex, in chapter order. Each one also sits on the prompts page, where it can be copied.
Open Codex. Ask for the join. Every row names its source: the land registry, the planning portal, the company register, with the page and the date. A company name is written as a company, never as an owner. Nothing reaches the sheet without its source.
Open Codex in the engine folder, where target.md from the last chapter sits: one page naming
the streets, the asset type, the trigger. Connect three servers. Chrome
DevTools MCP drives your own Chrome and lists every request a page makes, so where a portal
fetches its results as a data file and then draws it, Codex reads the file instead of scraping
the drawing. Firecrawl MCP crawls a planning portal whole, without you pressing next. Google
Sheets MCP is where the list lands; budget fifteen minutes for the Google sign-in it needs.
Then say what you want:
Read target.md. For every asset in it, build one row from the public
record and write where each fact came from: the land registry for who
holds the title and since when, the planning portal for who applied to
change the building and when, the company register for what sits behind
a company name. Open each portal in Chrome; where the page loads its
results as data, read the data, not the drawn page.
Where a portal is plain pages, crawl it with Firecrawl. Write the owner
exactly as the register spells it, and mark each row person or company.
Never guess a person behind a company. Put the page and the date on every
row. Write the rows to a Google Sheet called Owners, and report three
counts: rows built, rows where the owner is a person, rows where it is a
company.
What comes back is a script, a run over the patch and a report with three counts. The sheet called Owners holds one row per asset: the owner as the register spells it, person or company, the page and the date. The company rows stay; the human behind each is chapter 4, starting from the page.
Three honest limits, which Codex will tell you about. The recorded owner is often a company, and this build does not try to see through it; a row marked company is a true row. Every register is its own site with its own search, so a reader built for one stops at its border; the public county scrapers each cover one county, the most-starred last pushed in December 2022 (https://github.com/codefornola/assessor-scraper). And the one live build nearby, PropertyWebScraper (https://github.com/RealEstateWebTools/property_web_scraper, pushed July 2026), reads listings; a search of its source found no file that knows the word landlord. It can tell you what is on the market, and nothing about who owns the street.
The browser server reads whatever your Chrome is signed into, by design (https://github.com/ChromeDevTools/chrome-devtools-mcp). Run it in a Chrome with only the portals open.
Open Codex. Ask for the page. Map the company site with Firecrawl, scrape the people page, and only that page. A directory name is not a rung. When a page needs a click, Playwright opens it. Every name carries its page and date, or reads none.
Open Codex in the engine folder, where shortlist.csv from the last chapter sits: twenty
companies, each with the reason it is worth a call and the entity recorded on the title. Then
say what you want:
Read shortlist.csv. For every company, find its own website: the domain on
the recorded document if there is one, otherwise the site that names both
the company and the asset. Use Firecrawl to map the site and find the page
that lists its people: a team page, a leadership page, an about page with
names on it. Scrape that page and only that page. Take the name and title
of the person who runs the company. If the page needs a click to show the
names, open it in Playwright and take a snapshot instead. Never take a name
from a directory, a data vendor or a social profile. Record the name, the
title, the page it came from and the date you read it. Where no page names
a person, write none. Write people.csv, and report three counts: named from
the company site, none, and sites you could not find.
What comes back is a script, a run over the twenty and a report with three counts. people.csv
holds one row per company: the name, the title, the page and the date. Load it into the CRM. A
row that reads none is a company the next stage reaches another way.
Firecrawl maps a site and returns its pages as text; its hosted server runs without a key on a rate-limited free tier, enough for twenty companies. Playwright reads a page as a tree of what is on it, so names that appear after a click still come through.
The rule that matters is the one about the source. Book one in this series learned it on its own list: a name from the company's own page held up; a name from an aggregator did not. That is why the instruction reads one page and refuses the rest.
Three honest limits, which Codex will tell you about. A holding company that exists only to hold often has no site, and Codex writes none rather than guessing. A site with a contact form and no names is the same. And a company register may list officers, but whether the officer named is a reachable human or a service that files for the company was not tested for this book, so the chapter claims no rate. Use the register as a second door, recorded as its own rung.
Open Codex. Ask for your voice. The twenty come in from the sheet with their reason. Your own past messages come in from disk as the voice. Every draft carries one fact from the row and nothing the row does not hold. You read each before anything sends.
Open Codex in the engine folder. The Owners sheet from chapter 3 is there, with its reason
column, and reach.csv from the last chapter, with each person's basis and hours. Make one
folder now, voice: twenty or thirty messages you wrote and would send again, one to a
file.
Connect two servers. Google Sheets MCP, the community server taylorwilsdon/google_workspace_mcp, reads the rows and writes the drafts back; budget fifteen minutes for the Google sign-in. The Filesystem server from the reference repo reads the voice folder. Then say what you want:
Read the top twenty rows of the Owners sheet by score, with the reason
column, and read reach.csv for each person's basis and hours. The voice
folder holds messages I wrote myself; the drafts must sound like them,
my length and my openings. Write one message per row. Open with my name
and why I am writing, in the words the basis allows. The second sentence
is the one fact in the reason column, stated as the record states it,
with no adjective on it. Never add a fact that is not in the row. Never
write hope you are well or just checking in. End on one question about
the fact. Write each draft in a draft column beside its row with the fact it
used; leave the sent column blank. Report two counts: drafts
written, and rows where the reason was too thin to write from.
What comes back is a script, a run and two counts. You read the twenty before the afternoon is out, and the sent column is the button the next chapter presses.
The rule that carries the chapter is the second sentence. A recorded maturity, a tenure, a confirmed expiry: each has a public page behind it. The strongest objection to machine-written outreach is the recipient's:
"I open emails because I believe you spent time on me, which is precious, so I reply. If an AI generates cold emails, there's no real time spent, making personalization feel deceptive, which is bad for user experience." sherwinx, Hacker News, https://news.ycombinator.com/item?id=40876341
The only answer that survives it is a fact that is true and defensible. The reason column holds one; a template pack cannot.
The nearest public build is OpenOutSend (https://github.com/eracle/OpenOutSend, MIT, eight stars, pushed September 2026). It writes from a person's profile text, company and title, under a tone rule that reads "short and specific, like a real person wrote it, not salesy". It is built for a different trade: it needs a paid candidate list from its sister tool, and a read of its source found no property vocabulary.
Three honest limits, which Codex will tell you about. The drafts sound like the voice folder, so twenty messages you regret produce fifty more. A row whose reason is thin gets no draft, because a draft from nothing needs an invented fact. And no tool can tell whether you would defend the fact in a call.
Open Codex. Ask for the morning. A thin server on the Cloud API: the template tools, and two that read the quality rating and the sending limit. Templates approved the day before. Fifty sends. Every failure written by its error code, and a capped row never retried.
Open Codex in the engine folder, beside reach.csv and the chapter 6 messages. Meta
publishes no MCP server, so the build is a thin one of yours, a handful of HTTPS calls, in
the shape of two one-day community repos: tkhattar14/whatsapp-business-mcp (template and
analytics tools; https://github.com/tkhattar14/whatsapp-business-mcp) and
marco2901/whatsapp-mcp-server (a send and a webhook receiver;
https://github.com/marco2901/whatsapp-mcp-server). Read their tool lists, depend on neither,
and say what you want:
Build a thin MCP server on the WhatsApp Cloud API in the shape of the
two repos above: create a template, read its status, send it, receive
the webhook, read the quality rating and the messaging limit. Today:
submit the chapter 6 message as a marketing template with a variable for
the owner's name and one for the building, and stop until its status
reads APPROVED. Tomorrow: print the rating and the limit before sending
anything. Send only to rows in reach.csv whose basis is opted in, inside
the hours the row allows, one message per owner. Write every send and
every failure to sends.csv with its error code. On error 131049 mark the
row capped; never retry it. At the end print the rating again beside the
morning's. Report four counts: delivered, capped, failed otherwise,
replied.
What comes back is a server, a run and four counts.
Every rule it obeys is on a Meta page. "You can only send messages to WhatsApp users who have opted in to receiving messages from you" (https://developers.facebook.com/docs/whatsapp/cloud-api/guides/send-messages), so the run reads the chapter 5 basis column and nothing else. "You may only initiate conversations using an approved Message Template" (https://whatsappbusiness.com/policy/), and "Templates are automatically reviewed upon creation or after editing" (https://developers.facebook.com/docs/whatsapp/business-management-api/message-templates), a review that can take up to 24 hours, so the template goes in the day before.
The cap shapes the morning. "The per-user marketing limit adapts automatically over time based on a person's recent engagement levels" (https://developers.facebook.com/documentation/business-messaging/whatsapp/templates/marketing-templates/per-user-limits). It is the recipient's, shared with every business messaging them; when it is spent the send fails with error 131049 and nothing queues. Your own limit starts at 250 unique recipients a day and rises only while the quality rating holds (https://developers.facebook.com/docs/whatsapp/messaging-limits), so the run reads it before and after.
Two honest limits, which Codex will tell you about. The fifty voices of chapter 6 become one reviewed text with two variables. And marketing templates never reach US numbers, while the cap applies in full in the UAE and not in the EEA, the UK, Japan or South Korea (same page).
Twilio is the on-ramp if you would rather not stand up a Meta app: "Send and receive WhatsApp messages using the WhatsApp Business Platform and Twilio APIs" (https://www.twilio.com/docs/whatsapp), the same rules, its own fee on top.
Open Codex. Ask for the three fields. It reads the thread from the last chapter and writes timeline, finance and your third field, in their words. What was not said is written as unknown, never guessed. Nobody is sent a question. Every field carries its message.
Open Codex in the engine folder. The enquiry chapter 9 answered, and every message since, sits
on the contact in the CRM, with three fields left blank. Connect two servers. HubSpot's remote
server reads and writes contacts and the notes, emails and calls on them
(https://developers.hubspot.com/ai-tools/mcp). The Memory server from the protocol's reference
repository holds what each person said
(https://github.com/modelcontextprotocol/servers). Write fields.md once: three field names,
and what counts as an answer to each. The first two are the form's: the timeline, and where the
money stands. The third is yours; the form offers Price Range, chapter 9's reply asked how much,
and a commercial reader may want the intended use instead. Then say what you want:
Read every contact whose enquiry came in this week, with the whole
thread. Fill the three fields in fields.md, in the person's own words,
with the message each came from and its date. Where they said nothing,
write unknown. Never guess, and never send them a question. Record
what each person said in Memory, so the next run reads only new
messages. Where all three are filled and the timeline is inside a
year, set route to viewing; otherwise follow-up, with the reason in
their words. Report three counts: all three filled, some, none.
What comes back is a script, a run and three counts: on each contact, three sentences the person wrote, a route, and its reason.
The reason stays because the public builds throw it away: the best public attempt decides by matching substrings after the model finishes (https://github.com/Nishkal08/Real_Estate_Agentic_CRM-Whatsapp-Enabled), and the deepest public CRM writes one field, temperature, and discards its reasoning (https://github.com/InsulaCRM/InsulaCRM).
Three honest limits, which Codex will tell you about. A yes to the lender question from someone who used an online calculator reads as yes; only a person hears the difference. So does ASAP from someone with nine months left on a lease. And a HubSpot account with sensitive data turned on blocks the activities its server reads (https://developers.hubspot.com/changelog/remote-hubspot-mcp-server-is-now-generally-available), so the thread comes from the mailbox chapter 9 connected.
Open Codex. Ask for the timer. It reads each enquiry with an owner and nothing done in N minutes, and moves it, reason on the record. N is a ruling you make once. A lead never sits unowned, and never sits owned and untouched.
Open Codex in the engine folder. The enquiry chapter 10 routed to a viewing sits on a contact, with
the owner the rota gave it. Connect the CRM's own server. HubSpot's remote
server reads and writes contacts and the calls, notes and tasks on them, and reads owners and
teams (https://developers.hubspot.com/ai-tools/mcp). Follow Up Boss publishes no server of its
own; the live community one, written by a broker in Austin, covers the whole API, ponds
included (https://github.com/mindwear-capitian/followupboss-mcp-server). Write window.md
once: N, the minutes an owned enquiry may sit with nothing logged; what counts as action; and
the order a lead moves in, the next name in the rota, then the shared pool, then you. Then say
what you want:
Every five minutes, read every contact routed to viewing that has an
owner. Find the newest call, note, message or task the owner logged on
it. Where nothing has been logged for longer than the minutes in
window.md, move the contact to the next person in window.md, note on
the record who had it, how long it sat and who has it now, and create
a task for the new owner. Where an enquiry has no owner, give it one
the same way. Never delete anything and never message the client.
Report each morning: received, touched inside the window, moved, and
moved twice.
What comes back is a script, a schedule and four counts, and on every moved lead a note that says why.
Three honest limits, which Codex will tell you about. The timer reads what was logged, so a call from a personal phone that was never written down reads as no action, and the lead moves from someone who was working it; chapter 16 stops the logging depending on typing. A HubSpot account with sensitive data turned on blocks the activities the server reads (https://developers.hubspot.com/changelog/remote-hubspot-mcp-server-is-now-generally-available), so a run that sees nothing says so. And the Follow Up Boss server is one person's project with full write access; it can delete, and the instruction says never.
Open Codex. Ask for the shortlist. It reads the register you keep and what each client said, and writes a shortlist with one sentence per match. A match it cannot explain in one sentence is dropped. You read the list before anyone is told.
Open Codex in the engine folder. The register is the spreadsheet you already keep, one row per property. Connect it: for Excel, the community Softeria/ms-365-mcp-server (https://github.com/Softeria/ms-365-mcp-server); for Airtable, Airtable's own hosted server or domdomegg/airtable-mcp-server, which returns a hundred rows unless asked for more.
What the client said sits in two places: the three fields chapter 10 wrote, and the thread chapter 11 stored on the contact. Chapter 10 also recorded it in the Memory server from the protocol's reference repository (https://github.com/modelcontextprotocol/servers): one entity per client, each thing they said an observation. The sentence that fits no field, the driveway, goes there too. Then say what you want:
Read the register, every row, and tell me the total first.
For each client whose route is viewing or follow-up, read their three
fields, every observation on them in Memory, and the whole thread.
Shortlist at most three properties per client. For each, write one
sentence saying why this one for this person, in their words, and one
sentence saying what is wrong with it. Where a property misses a field
but answers something they said, keep it and say which sentence. Where
you cannot write the why in one sentence, drop it. Send nothing. Write
the shortlist in a sheet beside the register and report three counts:
clients with a shortlist, clients with nothing this week, matches
dropped as unexplained.
What comes back is the shortlist and three counts, waiting for you.
The one sentence is the whole stage. The deepest public build scores +25 for price, +25 for type, +20 for the zip code and +15 for the state, and tells the agent, never the client (https://github.com/InsulaCRM/InsulaCRM). Membership is exact, so a buyer who wants a three-bed at £500,000 scores zero against a £505,000 three-bed one postcode over. A model reading "somewhere for the RV" beside a row with a wide drive can say why.
Two honest limits, which Codex will tell you about. A model matching on prose can be too kind; that is why the unexplained count is reported and why a shortlist stops at three. And a call nobody wrote down matches nothing.
Open Codex. Ask for the witnesses. The tool that saw the event writes it: the calendar the meeting, the mailbox the email, the webhook the message. Nothing is summarised and nothing is invented. A contact silent for thirty days is a count, never a nag.
Open Codex in the engine folder. Connect the CRM's own server: HubSpot's, at mcp.hubspot.com,
writes "calls, emails, meetings, notes, and tasks" on a contact
(https://developers.hubspot.com/ai-tools/mcp). Connect the calendar and the mailbox through
taylorwilsdon/google_workspace_mcp (https://github.com/taylorwilsdon/google_workspace_mcp).
The WhatsApp thread is already in chapter 8's webhook store. Write witnesses.md once: which
calendar, which mailbox, which number, and how a contact is matched, phone first, then email.
Then say what you want:
Every fifteen minutes, read the calendar, the mailbox, the message store
from chapter 8 and the call log. For each event whose other party
matches a contact in witnesses.md, write it on that contact once: a
meeting with its time, place and who came; an email with its subject
and body; a message with its text and direction; a call with its time
and length. Use the event id so nothing is written twice. Never invent
an event, never summarise one, never write on a contact you cannot
match; list those in nomatch.md. Each Monday, count every contact
with no event in thirty days and print the count beside the total, with
their names.
What comes back is a script, a schedule, and two Monday numbers with names under them.
Three honest limits, which Codex will tell you about. Calls are the thin part: no public server
executes a call log (Twilio's hosted one "does not execute API calls on your behalf",
https://www.twilio.com/docs/ai/mcp), so a call is written by a script against the Voice REST
API of the number you rent, or the CRM's own calls endpoint; a call from a personal mobile
is seen by no API and written by nobody, and the Monday number shows it as silence. A HubSpot
account with sensitive data turned on blocks the activity objects
(https://developers.hubspot.com/changelog/remote-hubspot-mcp-server-is-now-generally-available).
And Salesforce is the exception: its vendor server has one data tool, run_soql_query, and no
record write (https://github.com/salesforcecli/mcp), so there the writing goes by script.
Open Codex. Ask for the chase. The stage is read from the signature server itself and written to the deal. A reminder is one tool call. Days since anything moved is the number, read per deal. It is printed, never sent.
Open Codex in the engine folder, where the deal chapter 17 pitched sits at agreed. Connect the signature vendor's own server. Docusign's, at mcp.docusign.com/mcp, is "now
available in Open Beta" and exposes the eSignature API
(https://developers.docusign.com/platform/mcp-server/). PandaDoc's, at
mcp.pandadoc.com/v1/mcp, tracks status and can "Send reminders for all contracts tagged
'Q4-2024' that haven't been signed yet"
(https://developers.pandadoc.com/docs/what-you-can-do-with-pandadoc-mcp). Then the CRM's
own: HubSpot's reads and writes deals (https://developers.hubspot.com/ai-tools/mcp). Write
deal.md once: the stages an agreed deal passes; who owes the next thing at each; the tag on your deal documents; and N, the days of silence you will tolerate.
Then say what you want:
Every morning, read every deal at agreed or beyond. Read the status of
its documents from the signature server, by the tag in deal.md, and
write the stage to the deal in the CRM, reason on the record. Find the
newest thing on the deal: a signature event, a note, a call, a message.
Print days since it, per deal, beside who owes the next
thing. Where a document has sat unsigned longer than N days, send the
signature server's own reminder once, and note it. Never send anything
else to anyone, never touch a price, never write a counter, never move
a deal to won or lost. Report: agreed, moved this week, silent past N
days, reminders sent.
What comes back is a script, a schedule and a table sorted by days.
Three honest limits, which Codex will tell you about. The Docusign server is a beta, and its page says so in capitals, provided "AS IS" and "AS AVAILABLE" without warranty. The lawyer and the lender answer on email, which no signature server sees, so a deal waiting on a lawyer reads as silent until chapter 16 writes the email on the deal. And the counter is a conversation the server never hears.
Open Codex. Ask for one table. Portal spend off the portal, leads and deals off the CRM, commission off your sheet. Every count carries its total. A number nobody wrote stays blank, never zero.
Open Codex in the engine folder. Connect a Sheets server, taylorwilsdon/google_workspace_mcp
(https://github.com/taylorwilsdon/google_workspace_mcp), and the CRM server, HubSpot at
mcp.hubspot.com (https://developers.hubspot.com/ai-tools/mcp). The portal publishes none, so the
browser reads it: chrome-devtools-mcp drives your own Chrome
(https://github.com/ChromeDevTools/chrome-devtools-mcp), where list_network_requests shows the
JSON behind the chart. Write monday.md once: the stage names, the sheet tab, the week that
counts. Then say what you want:
Every Monday at seven, read the portal lead dashboard and the spend
beside it in the open browser; from the CRM every deal that changed
stage in seven days; and the commission tab of the sheet. Write one
table: per stage the count in, the count out, and the total sitting
in it, so every count has its total beside it, plus a row for portal
spend and one for commission raised. Print each stage conversion
this week beside the same stage last week, and name the ONE stage
whose rate fell furthest. Where a value was never written print a
dash, never a zero, and list what you could not read.
What comes back is a script, a schedule and one table.
Three honest limits, which Codex will name. The portal read runs against your own logged-in Chrome, a tool that "exposes content of the browser instance to the MCP clients", so it runs on a screen you watch. A HubSpot account with sensitive data turned on blocks activity objects (https://developers.hubspot.com/changelog/remote-hubspot-mcp-server-is-now-generally-available), so that half reads short and says so. And the table is only as true as chapter 16 made the record.
There is no benchmark either: no conversion rate for this trade was found published anywhere, so your week compares only against your last.