How we find short-term rental owners, reach out to them, and keep every single step safe and approved.
A "lead" is a person we're trying to reach — a short-term rental owner. Every lead follows these exact steps. Nothing skips ahead.
We spot a short-term rental owner (Airbnb or VRBO host) we'd like to work with. Skylar adds them to the CRM as a lead — our word for a person we're actively trying to reach.
👤 Skylar does thisAttio is our memory — a database that stores everything about each person: their name, their phone number, every message we've ever sent, their replies, and whether they've ever asked us to stop. This is the source of truth.
⚡ AutomaticNothing happens automatically. Skylar runs a command called /enroll — this is how a lead actually enters a campaign. It creates the planned messages and sets the schedule. Skylar writes what each message says, picks the timing, and chooses who gets it. Claude (the AI) can suggest wording or fill in personalization, but Skylar is always the author and the one who kicks it off.
👤 Skylar runs /enroll ·🤖 Claude assists if askedEvery message needs a real human to approve it before it can go anywhere. Nothing sends on its own. If Skylar says no, the message disappears. If Skylar says yes, it gets scheduled. Creation = approval. No exceptions.
👤 Skylar must approve every sendThe Worker — a tiny robot program that runs in the cloud every 60 seconds — sees the approved message and sends it at the right time. It uses SignalHouse (our phone service) to actually deliver the text. Like a very reliable postal worker who never sleeps.
⚡ Worker + SignalHouse handle deliveryWhen the lead replies, the Worker catches the incoming message and logs it in Attio immediately. All future texts to that person are put on hold until Skylar reads the reply and decides what to do next. A reply could mean anything — the machine doesn't guess, a human decides.
⚡ Worker logs it ·👤 Skylar decides next moveIf the lead says stop, unsubscribe, opt out, or anything like it — they are removed from every channel instantly and permanently. No one can override this. Not Claude, not Skylar. It's built into the code.
🛑 Blocked forever on all channelsSix main parts. Each one has exactly one job. They talk to each other but can't do each other's jobs.
15 rules across 3 groups. These aren't suggestions — they're written into the code. Three groups: rules that protect the lead, rules that keep humans in charge, and rules that keep data clean.
🛡️ Group 1 — Protect the lead (machine enforces these automatically)
Text, call, or verbal — any opt-out blocks that person on every channel instantly and permanently. Even "stop" said out loud on a call is caught from the call transcript. No override. No undo.
The moment a lead writes back, all future messages are frozen instantly. The machine doesn't guess what it means. It waits. A human reads it and makes the call.
Before every text, the Worker runs a full checklist: opted out? Business hours? Reply pending? Daily cap hit? All must pass. One fail = no send. Always.
Weekdays, 9 am–5 pm in the lead's local time zone. A message due at 7 pm waits until 9 am next morning. Checked every single send.
Hard limit on texts per day. Once hit, the machine stops sending entirely — no override. Prevents a bug from blasting hundreds of people accidentally.
Every message has a unique ID. The Worker checks before sending — if it's already gone, it skips. A bug or retry can never double-text a lead.
✋ Group 2 — Keep humans in charge (machine helps, humans decide)
When Skylar runs /enroll (the command that adds a lead to a campaign), that act is the approval for the whole sequence. The Worker then runs each step automatically — no per-message clicking needed.
Skylar runs this command daily. It surfaces every frozen lead, every unread reply, every waiting decision. If she skips it, frozen leads stay frozen safely — nothing moves without her.
Claude writes messages and suggests next steps. Humans review anything consequential — a new campaign, a hot reply, an unusual situation. The AI does the legwork; the human makes the call.
If a rep hits a bug, they stop. Don't work around it. File a bug report in GitHub Issues (the to-do tracker) and wait for admin to fix it right.
One designated safe test number exists. All test sends go there only. A real lead's number is never used to test anything. Full stop.
The screen reps use (the Desk) holds no passwords or API keys. All keys live backstage in the Office. The Desk is fully untrusted — by design.
🗂️ Group 3 — Keep data clean (where things live and who sees what)
Any info about a real lead lives in Attio (the CRM database). Don't copy it into a doc, a chat, or a spreadsheet. It will go stale. Trust the CRM.
Rules, plans, specs — anything that needs to survive past a chat window goes in the GitHub repo (the code home). Not in a Slack message or someone's head.
Every rep sees only their own leads. The system blocks access to anyone else's book. "That's not your lead" — and it means it.
The engine is simple: a Worker that runs every 60 seconds + Attio memory + Claude brain + any provider we plug in. That unlocks a lot. Here's the full picture — what's live, what's coming, and what's possible the moment we wire it up.
Write it, schedule it, send it. Personalized per lead. Delivered by SignalHouse.
Record a short video on this machine with Cap, send it via text link. Feels personal — because it is.
System dials via SignalHouse. Call logged in Attio automatically.
⚠️ Autodialer (fully automated dialing without a rep clicking) still needs full end-to-end testing.
Smartlead (our email tool) is live. Sequences are being finalized. The only thing left is completing the inbox warmup period — after that, ready to go live.
⚠️ What's left: Complete email inbox warmup. Then go live.
Drop a pre-recorded audio message straight into their voicemail — no ringing, no awkward silence.
Trigger a printed postcard to a lead's address using a service like Lob. Stands out in a noisy inbox world.
A reply instantly freezes all future texts to that lead. Waits for Skylar to read and decide. Never assumes what a reply means.
A multi-step plan: text day 1, video day 4, follow-up day 10. Enrolled once — the Worker runs it automatically until a reply or the last step.
Fire a message on a specific date — seasonal check-in, "heading into peak season," or an anniversary of when they first reached out. The Worker checks every 60 seconds and sends any message whose date has arrived.
Leads that went cold 60+ days ago automatically get a fresh outreach — different message, different angle. Wake up the dead list.
Send version A to half a group, version B to the other half. The testing part is built. Automatic winner rollout (machine picks best and switches to it) is not yet implemented. Live end-to-end test still needed before this is production-ready.
⚠️ What's left: Build auto-winner rollout. Run a live end-to-end test across a real campaign.
Connect Calendly (scheduling tool) so when a lead says "yes" to a call, they get a booking link instantly — no manual back-and-forth.
Machine creates a to-do: "call Sarah today." Rep clicks, system dials. Call logged automatically in Attio.
Same as the call task — but queues a text instead. "This lead hasn't heard from us in 14 days. Text them today."
Queue a reminder: "Record a personal Cap video for this lead today." Opens Cap pre-loaded with context on who you're recording for.
"Check in with Mike in 30 days." Machine pings you on day 30. You decide what to do — text, call, or skip.
Machine queues: "Send this lead a gift card or Amazon item." Connect a gifting service and it ships automatically on approval.
Machine finds the lead's LinkedIn and queues a connection request task for the rep. Multi-channel without doing it manually.
Claude reads every reply and auto-detects "stop," "remove me," "wrong number," or call refusals. Acts immediately — no human needed.
AI reads a reply and suggests what it means: "Interested," "Not now," "Wrong number," "Hot lead." Skylar sees the suggestion before deciding.
AI gives each lead a score based on their profile: listing count, market, engagement history. Focus energy on the hottest prospects first.
Auto-generate a "what's happening in your market" snapshot for a lead's city. Send it as a value-add before asking for a call.
Calculate what Leveled could earn this specific owner based on their listings and market. Personalized proof point baked into the first message.
After running A/B tests across campaigns, Claude learns which messages work best for which markets and lead types — and uses that automatically.
Claude reads through past conversations and flags leads you should have followed up on but didn't. "This person seemed interested 3 weeks ago and nothing happened." Surfaces hidden revenue sitting in the existing book.
⚠️ What's left: Build the conversation analysis logic. Define what "missed opportunity" looks like in code.
Claude listens to call recordings and reads outreach history, then gives specific coaching: "You always lose momentum on the 3rd follow-up — here's why and what to say instead." Gets smarter the more calls and messages it analyzes.
⚠️ What's left: Wire call recordings into the analysis pipeline. Build the coaching output format.
Skylar runs /start-sales each morning — a pre-built checklist showing every frozen lead, every reply to read, every message waiting for a decision. One screen, 60 seconds.
⚠️ What's left: Formalize the daily review flow fully. Live testing to confirm it shows everything Skylar needs.
For any campaign: how many enrolled → sent → replied → booked. See exactly where leads drop off.
⚠️ What's left: Build the report renderer. The JSON data contract is already spec'd — needs the display layer built.
See every lead and where they are: Initial Contact → Engaged → No Response → Lost. Across all campaigns at once.
⚠️ What's left: Build the pipeline report renderer. Same as campaign funnel — data contract is spec'd, display layer needed.
Tracks the key numbers across the whole acquisition process — reply rate, book rate, cost per booked call, best-performing market, best-performing message type. Then surfaces the single highest-value move: "If you fix X, you get the most new clients for the least effort."
⚠️ What's left: Define which metrics matter most. Build the calculation layer. Build the "highest-value move" recommendation output.
A "campaign" is a named outreach plan — a group of leads, a series of messages, a goal. Here's how to set one up so it actually works.
Before you launch — the checklist
Personalization — make every message feel one-on-one
Use merge tags — little placeholders that get swapped out for each lead's real info when the message sends. Write one message, send a thousand personal ones.
Name tags
{{first_name}}
→ "Hey Sarah, ..."
{{full_name}}
→ "Hi Sarah Johnson"
Market & location tags
{{market}}
→ "owners in Newport Beach"
{{city}}
→ "your place in Scottsdale"
Property tags
{{listing_count}}
→ "you manage 3 listings"
{{platform}}
→ "your Airbnb" or "your VRBO"
Conditional block — show different text per group
Example — what a personalized first text looks like
Message template (what Skylar writes)
What the lead actually receives
Everything has one home. Put it in the right place and the whole machine stays clean.
Where things live
Every lead's name, phone, history, replies, and opt-out status. If it's about a real person, it lives here. Attio is always the source of truth.
If something is broken or needs to be built, it becomes a GitHub Issue (a to-do ticket). Not in a chat message. Not in someone's memory. In the tracker.
When the system fires an alert — a reply came in, something failed, or the daily health check runs — it goes to Discord. That's where the team stays in the loop.
The daily rhythm (what Skylar does each morning)
Golden rules for staying clean
These are the exact words we use in this system. Use them the same way every time so nothing gets lost in translation.
People
Any human contact stored in the CRM. The raw record. Not yet being worked for a sale.
Don't say: contact, record, prospect
A Person we're actively trying to close. Someone being worked right now for a sale.
Don't say: prospect, deal
The full list of Leads a rep is allowed to work. Your assigned territory.
Don't say: assigned records, territory list
The rep who is responsible for a specific Lead. One lead, one owner at a time.
Don't say: assignee
A user who can see the whole team's Book and move Leads from one rep to another.
Don't say: admin (when talking to reps)
Someone with access to the code but no Badge (sign-in). Can only use Practice mode — no real data.
Don't say: unauthorized user
Work
Any recorded interaction with a Lead — a text sent, a call made, a note logged. The history.
Don't say: touch (to reps), event
The next approved action queued up for a Lead. "Text them on Thursday." One lead has one next step at a time.
Don't say: planned touch, task payload
Moving a Lead from one rep to another. Logged in the Paper Trail so nothing is lost.
Don't say: share, transfer
The full conversation tied to one Lead and their current Owner. One thread per lead.
Don't say: chat context, last conversation
One named outreach effort — a target group, a message shape, and a channel (text, email, etc.).
Don't say: blast, batch, run
A reusable message shape — like "first contact" or "follow up after 14 days." A template you run again and again.
Don't say: module, workflow template
The defined group of People a Campaign is targeting. "All STR owners in Phoenix with 3+ listings."
Don't say: segment (to reps)
Access & System
The terminal — the command-line tool where a rep runs the CRM. Type commands here to do anything in the system.
Don't say: CLI, client app
The back-end API — the trusted server that holds keys, enforces rules, and talks to SignalHouse and Attio.
Don't say: backend, Cloudflare Worker (to reps)
Your 7-day CRM sign-in. Proves who you are. The Office checks it on every command to confirm your access.
Don't say: token, credential, API key
Fake data and safe commands. Use this to train or test. Nothing in Practice can reach a real person.
Don't say: staging, fixtures
The automation that safely moves messages. The Cloudflare Worker that runs every 60 seconds and sends due texts.
Don't say: plumbing (for a specific send path)
The internal log of every change and every denied action. If something happened in the system, it's here.
Don't say: audit log (to reps)