Everything needed to take a new property-management client from signed to fully live on Clara: the must-haves, the setup steps, how knowledge is collected and applied, how we prove it, and how we turn it on in stages.
Rewritten 2026-09-22 from two weeks of sessions, PRs and incidents. Built from the Camellia (JP&Co), Situs Group and Western Slope onboardings. One page per initiative: add to this page, don't start a new one.
Contents
A Claude session or a human engineer onboarding the next client without Fede in the room. Work top to bottom: collect the answers in section 2 from the client first, run the setup in section 3, build and prove knowledge (4 and 5), then turn on in the stages of section 6. Every rule here came from something that broke. When a rule and a newer dated Fede ruling disagree, the newer ruling wins; fix this page in the same turn.
"All the learnings I've had in the last two weeks condense them in one document that is useful for both Claude AI and for a human engineer. So if someone else is onboarding another client, I don't have to be involved directly."
Fede, 2026-09-22, session 010
This replaces the three older checklists (the repeatable playbook, the 18-step pre-go-live list and the Situs list). An item is done only when its proof is pasted on the client's go-live tracker row (for Western Slope, the go-live tracker). Merged code is not proof.
| Must-have | Why (the incident it prevents) | Verify |
|---|---|---|
| One company record, created from the AppFolio pull. Never a hand-typed placeholder. | A Sep 5 placeholder and the real Sep 12 record coexisted for ten days at Western Slope; cleanup took an afternoon and 2,049 deleted rows. | One org for the client in prod; its name matches the AppFolio database. |
| Isolation proven before the client's admin is invited. | 2026-09-07: JP&Co's data showed under Western Slope's new org, and a settings endpoint returned every company's details to any admin. | Sign in as the new admin; only their own properties and people are visible. |
Clara has her own AppFolio user at this client (clara+<company>@propflowai.co), and its AppFolio user number is saved once on the company connection. | 2026-09-21: Western Slope's cards could not be assigned to Clara because the user was only set per property, at Willows. | One robot login, timestamped. Western Slope: user 540. |
| Every home has a time zone. | 2026-09-21: 69 homes had none, so quiet hours ran on Central time and a text went out at 7:00 AM Mountain. | org.timezone plus each property read back. Automatic inference at import is not built yet. |
| Email signature details set once at the company. | 2026-09-21: single-family homes showed the rented home's street address as the email header and signature. | A real Clara email, read by eye. |
| Import brought only records from the last 30 days; PM reminders are off. | 2026-09-16: 1,065 guest cards (762 over 90 days old) came in, and an hourly reminder sent 100 emails to the client's inbox in one hour. | Import counts by age; pm_action_reminders.enabled reads false. |
Once a client forwards their main line to Clara, that number is no longer a safe transfer destination: it rings straight back into Clara. Never set any transfer destination to a number that forwards into Clara. Person-transfers go to people. "Everything else" destinations live at the company level, not per property.
| Must-have | Why | Verify |
|---|---|---|
| Review every call type with the client: leasing, maintenance, emergency, everything else. For each, either name who gets the call (company-level for centralized clients, property-level for on-site teams) or confirm that taking a message is fine. Nothing set means Clara takes a message. | Fede, 2026-10-07. An emergency left unset is the one to double-check. | Each call type has a named destination or a recorded "message is fine" from the client. |
| Leasing forward: a company ring list of people, in ring order, used during office hours. After hours, take a message. | Missed at Western Slope go-live (Fede, 2026-09-22). | A real call asking for a person reaches the first person on the list. |
| Maintenance: the client's call center, or an emergency on-call line plus a message for everything else. The client's own route outranks caller recognition. | 2026-09-17: repair callers Clara recognised were handled by Clara instead of the client's call center. The emergency on-call list is built but not configured for any client yet (2026-09-22). | A recognised-caller repair call is forwarded, and no work order is created. |
| "Something else" catch-all at the company level: people, never the client's own forwarded main line. | 2026-09-22: Western Slope's catch-all pointed at their forwarded main line; three real calls bounced and dropped (Twilio sids CA765a4f88, CA14680d90, CA181dd9fd). Clara now refuses such destinations and takes a message (#10795). | A real "something else" call reaches a person. |
| We know the staff phone system before any ring list is on. | 2026-09-21: Western Slope's RingCentral answers in 1 to 2 seconds; the "press 1 to accept" prompt dropped staff. Plain forward is now the default (#10567). | A real answered call to a staff member, recorded. |
| No voice tool field can resolve to an empty value. | 2026-09-17: one empty dynamic field made the voice vendor reject the whole tool set; every call on every customer line failed for about two hours. | The empty-variable test is green on the client's agent. |
| Every destination proven with a real call placed after the client's forwarding is on, recording kept, before Fede switches anything on. | The loop above only exists once forwarding is on, so an earlier test proves nothing. | One call id per destination on the tracker row. |
| A bench call on the client's real number reads back the company, the property and the homes. | A company-scoped routing record once skipped the property lookup; Clara had no property context. | Call context printed with no empty fields. |
| Must-have | Why | Verify |
|---|---|---|
| Leasing mailbox connected with Exchange Full Access and Send As granted first. | 2026-09-15: three failed connects over days at Western Slope. | One read and one send through the connection. |
| The client switches on AppFolio's own guest-card email notification. | Not one Western Slope lead email produced a guest card: all were listing-site relays. | One guest card arrives in the connected mailbox. |
| Calendar connected; a booked event is checked through the calendar's own API. | A tour Clara confirmed on the phone never reached the agent's calendar; a stale connection failed silently. | Bench booking, event found; cancel, event gone. |
| Every home resolves a staff-notice recipient on the client's domain. No PropFlow test mailbox. | 2026-09-17: tour notices for 69 of 70 homes reached nobody; others went to an engineer's smoke mailbox. | Resolved recipient listed per property. |
| No shadow, redirect or test-mode switch on outbound email. | A leftover shadow switch rerouted every Western Slope staff notice from day one while sessions reported "email on". | A delivered event (timestamp and message id) at the client's real address. |
| Activity Slack channel registered by its permanent id. | The channel was renamed and the app, addressing it by name, went quiet. | One call posts into the channel. |
| Must-have | Why | Verify |
|---|---|---|
| Every front-door property has an AppFolio property behind it, or an explicit "nothing is written back" rule. | Write-back to Western Slope was impossible until the robot account was applied and a mapping existed. | Mapping read back per property. |
Lead source decided: which inbound leads Clara answers (email or appfolio_guest_cards). One trigger, never two. | Two triggers answer the same lead twice. | scripts/set-org-lead-source.ts --org <id> (read mode). |
| Prospect record owner set to AppFolio when AppFolio owns the lead. | 2026-09-20: listing-relay emails minted duplicate PropFlow leads next to AppFolio's own cards. | GET /api/admin/companies/<id>/prospect-record-owner. |
| AppFolio writes are proven at the Willows (test property 45), never in a client's live database. | AppFolio behaves the same across clients, so a Willows proof counts for all. | Willows run linked on the tracker. |
| Must-have | Why | Verify |
|---|---|---|
| Every item on the core leasing checklist (section 4) is filled from the client's answers. | Western Slope's review never asked for the application link because no fixed list existed. | Checklist shows no empty must-have. |
| Company facts and every per-home exception are loaded, and both layers are read back. | 2026-09-16: exceptions never loaded; Clara told a caller a lockbox-only home tours in person. 2026-09-21: a check that read one layer wrongly reported "never applied". | npm run knowledge:verify-live: 0 missing, 0 unplaced. |
| No client-verified figure can be overwritten by a second source. | 2026-09-21: a sync recomputed the application fee from charge codes; a prospect was texted $27 against the client's $40 (fixed in #10572). | Approved fee equals the live field on every property. |
| Office hours and tour hours read back live, separately. | Evening and weekend tours were refused because tour slots read reception hours. | office_hours and tour.hours printed for company and property. |
| Must-have | Why | Verify |
|---|---|---|
| One real lead in the client's own shape runs end to end: a fresh card created by AppFolio, the first email, a reply, a text to the line. | 2026-09-21: every proof ran on Willows and Camellia shapes; five defects appeared on Western Slope's first real single-family leads. | Message ids and call id on the tracker row. |
| One bench contact per home exception, on phone, text and email. | A gold-set pass shows Clara handles the content; only a live contact shows she reads it. | Three transcripts per exception. |
| Every bench persona dials from its own number; no real person's number or mailbox as a test identity. | Personas sharing one number were merged by caller recognition; a repair note leaked into a leasing email. | The persona-to-number list for the round. |
The order that worked. Each step says how, and when it counts as done.
| # | Step | How | Done when |
|---|---|---|---|
| 1 | Kick-off: send the client the question list in section 2 and ask for AppFolio API access. | Fede sends the API-access email. The bot/system account list (which AppFolio users are automation) is a kick-off input, never guessed: one shared assistant login looks exactly like a bot. | Answers in writing. |
| 2 | Client adds Clara as a user in their AppFolio. | One login per client, never shared, never a person's account. No financial or banking permissions. SMS MFA with a remembered device. Treat AppFolio like a careful human: reuse sessions, bounded retries, one session holder. | Robot login succeeds; Clara's AppFolio user number saved on the company connection. |
| 3 | Create the company from the AppFolio pull. | POST /api/onboarding/pms/appfolio/import; dry run scripts/appfolio-import-dry-run.ts. Needs Reporting API credentials: there is no browser-only path yet (the Situs blocker, 2026-09-20). 30-day window by AppFolio's own date. | One org, properties and homes in prod, each with a time zone. |
| 4 | Isolation check, then invite the client's admin. | PropFlow's own org-scoped invite with a typed 6-digit code. The admin invites their own team. Only Sean, Fede and Gera are platform admins. | Admin sees only their company. |
| 5 | Company-level settings, captured once. | Operating model (centralized or on-site), office_hours, tour.hours, org.timezone, signature details, escalation.owner. Nearest wins: a property overrides the company only where it truly differs. | Each value read back. |
| 6 | Connect the leasing mailbox. | Three valid shapes: a property's own mailbox (Camellia), a shared company mailbox (Western Slope, leasing@), or a mailbox PropFlow provisions (Yale 25 Station). Push or pull is decided automatically by probing Microsoft. Company mailbox is the default reply mailbox; a property mailbox overrides it. Check the subscription renewer covers company mailboxes. When a client's mailbox is connected, check for Tenant Turner lead emails and save the first one (with renter details removed) for the engineering team: Clara does not recognize Tenant Turner's format yet, and we have no sample to build from (2026-10-01). | One read and one send. |
| 7 | Connect the calendar. | Company calendar comes with the mailbox consent. Clara books on a leasing person's own calendar automatically when one is connected (engine logic, not a setting). | Bench booking found through the calendar API. |
| 8 | Bind the phone number and set routing. | Bind: POST /api/admin/phone-numbers (also binds the ElevenLabs agent, a third-party write). Dry-run resolveClaimAssignment and read the number's current agent first; a failed POST leaves a write-once half state that a re-POST does not repair. Ring lists: scripts/set-ring-list.ts --role leasing|maintenance|catch_all. Answer mode: scripts/set-human-handoff.ts --accept-mode. | Routing read back; no destination is a forwarded number. |
| 9 | AppFolio lead handling. | Lead source (scripts/set-org-lead-source.ts), prospect record owner (admin route), and the client's AppFolio guest-card notification switched on. | A guest card arrives and is recorded. |
| 9b | Turn off AppFolio's automatic showing texts (Fede, 2026-11-04). | Before Clara's reminders and follow-ups run at a customer, the customer switches off AppFolio's own showing confirmation, reminder and follow-up texts (the items are listed on the Situs ramp-up page). Fede: "tell the customer to turn it off (my preference)", then the same hour: "design it in a way that we work with or without AppFolio… Clara would need to check what was sent already". So this is a recommendation, never a precondition: Clara checks the thread before every tour or follow-up send and skips any step the renter already got from AppFolio or a teammate (design in progress on the mid-flow page). No code detects a PMS's automation config. | A staff-booked showing produces one text to the renter, not two, on a real card, with AppFolio's texts on or off. |
| 10 | Knowledge. | Section 4. | knowledge:verify-live green. |
| 11 | Proof, then turn-on. | Sections 5 and 6. Client turns on call forwarding; prove every destination that same day. | Fede says go. |
pkill patterns. Four parallel scout logins once killed each other.The flow: collect automatically → draft → our review first → client question link → client answers → apply to the right layer → verify what Clara actually reads → bench each exception. Human in the loop first, autonomous later.
| Source | Gives | Rule |
|---|---|---|
| AppFolio pull | Homes, listings, guest cards, work orders, lease templates, documents, settings | A deterministic script calls the APIs; the browser robot only where there is no API ("we should just call APIs", Fede, Sep 7). |
| Listings and website | Rent, deposit, utilities, promotions, apply button per home | Listing data, never knowledge. Availability comes from AppFolio's vacancy report by property and unit id, never address matching. |
| Leasing mailbox audit | Lead sources, staff reply habits, how staff send applications | Look before asking: "how do people apply" was a per-home button in AppFolio. |
| Uploaded documents | Lease form, fee schedule, house rules | The client uploads into the knowledge base (property page upload). Not taken by email. |
| Calls and messages | How staff actually answer | Context only. Never overrides the client's written answer. |
The must-haves are fixed before any client is looked at ("we should know what we need before hand", Fede, 2026-09-15). The pull marks each one found, conflicting or missing; the questionnaire covers the gaps and cannot skip a must-have. Draft in the Camellia shape: 12 to 20 leasing items, split into company policy, home fact, internal-only and settings. A 122-question flat list was rejected on Sep 8.
| Scope | Must-haves |
|---|---|
| Company | Office hours · phone, email, address · application fee · decision time · who applies, ID and income documents · income requirement · portable screening report · co-signers · vouchers and affordable homes · pet rules and deposit · assistance animals · lease terms · notice to vacate (days a tenant must give before moving out; ask every client, 30 is the common answer) · month-to-month notice · renter's insurance · smoking · tour method · tour booking hours · move-in payment · key handoff · after-approval steps · what Clara hands to a person |
| Home exceptions | Any company item that differs at a named home (e.g. lockbox tours, door-code key handoff, no pets) |
| Listing | Apply link · security deposit amount · utilities · specials · parking, laundry, amenities |
Western Slope audit against this list, 2026-09-15: 15 filled, 4 conflicting, 5 empty, 2 listing-only. A 397-question bank mined from 5,465 real inbound turns (Situs and Camellia) grades coverage for a client with no history: Situs scored 27% answered, 2% wrong, before any fill.
Consolidation before a human sees anything: documents and system settings auto-confirm; message-mined facts auto-confirm above an evidence floor (5 messages, 2 staff, no contradiction); identical values across homes become one company fact; live state (vacancy, balances, application status) is never a fact; a missing fact goes to the fill list, never a blank for the client to type into. What reaches a person is conflicts only.
"How do we like automatically create that from their AppFolio and their email and all the other sources we have, and then you send them a link with the questions, with a human in the loop first. So we review it, but eventually autonomous."
Fede, 2026-09-22, session 010
| Layer | Holds | Where it lives |
|---|---|---|
| Company | The general policy | Org node: ORG#<id> / ATTACH#setting#knowledge.section.* |
| Property | Only its exceptions. A property value beats the company value (Fede, 2026-09-14) | PROP#<id> / KNOWLEDGE |
| Listing | What one home adds: rent, deposit amount, utilities, promotions | The listing, never knowledge |
scripts/knowledge/load-knowledge-gold-set.ts --apply places every approved fact or refuses to finish. apply-knowledge-review (#8650) applies a finished review, dry run by default, and prints a before/after diff.Hours ended up in five places with three values because a knowledge pass hand-typed "Closed weekends and holidays" from the website. The rule: office_hours answers when reception is staffed; tour.hours answers when tours can be booked and falls back to office hours when unset. Never merged. Every channel reads the same resolver. Onboarding writes the setting once from the client's answer. Hand-typing a day or time range into knowledge is forbidden when a structured setting exists. A build check that fails hour-like text in knowledge is an idea, not built.
Fede reviewed the first machine-drafted knowledge base for Western Slope entry by entry. Every rule below is a mistake the draft made. The script, the draft generator and the review page follow them from now on. Result: Western Slope knowledge base.
Western Slope's first real self-guided tour escalated three questions to the PM that every customer must answer at onboarding; Fede: "we should already know all this."
An onboarding is not complete while any of these is missing; the gap shows as an escalation to staff on the first real prospect.
No rule above is contradicted by a newer ruling. One status note in rule 13 is dated: the application-link mode moved to the company level on 2026-09-19 (Fede: "this should not be per property"), with a PMS-generated option (leasing.applicationLinkMode). The rule itself stands.
The test that keeps these rules alive: western-slope-knowledge-gold-set.json holds Jay's 26 raw answers and the 24 entries Fede approved. A draft generator must reproduce those entries from those answers (topic, tier, every figure) before it merges. Verbosity budget on top: voice one figure and one date per turn; text answer plus figure plus link; email full.
npm run knowledge:verify-live -- --gold <gold-set.json> --property <front-door-property-id> # renders exactly what Clara reads, diffs it against the approved file. # must print 0 missing and 0 unplaced; prints how many answers it compared # (zero compared = failure). Refuses to run if the building map names an unknown building.
knowledge-exception-* scenarios in scripts/voice-harness/scenarios/), answered from the exception, not the company rule.scripts/onboarding-harness/knowledge.ts runs create, load, verify red-before and green-after on a scratch org.The idea: managers already type building facts into the notes on each property and home record. Clara reads them on the same 6-hour pull, keeps the lasting renter facts, keeps staff guidance private, and never takes a price or availability from a note. A local trial on both customers' real notes worked. One rule needs your call: which source wins when two disagree.
No new route: same report, four columns we drop today.
| Column | Western Slope | Situs |
|---|---|---|
| Building notes | 49 of 102 buildings | 24 of 69 |
| Home notes | 66 of 260 homes | 22 of 644 |
| Maintenance notes | 2 | 0 |
| Repair-request instructions | 55, one shared text | 13, one shared text |
A fifth column, showing settings, says "Default Settings" on all 171 buildings, so there is nothing to read.
| Renter facts in the notes that Clara can't answer today | Western Slope | Situs |
|---|---|---|
| Today | 49 | 28 |
| After the trial | 2 | 0 |
Gera's data grade for Western Slope is 70 of 100 today; it was not re-graded with the notes added.
| Decision | Recommend |
|---|---|
| What gets loaded | Lasting facts only; dated lines never |
| Which source wins | Your order, but a building's own note beats a company-wide answer, except fees, deposits and screening |
| Add "2858 C 1/2 Road" as an alias for Ember Estates by hand | Done 2026-11-03 (Fede: by hand for now). Backtest on the last 30 days: the 12 messages that missed before now land on Ember Estates, 0 other changes. |
Worth building? Yes, with the source rule above. At Western Slope 1 lasting fact in 7 disagrees with something we hold, mostly normal building exceptions; at Situs 1 in 22.
1. What gets loaded. Recommend A.
Trial: 84 of 629 facts were dated and left out. A second reader disagreed on 15; read by hand, the trial was wrong on 2 (0.3%). One of those 2 is why Western Slope's run is RED: a current lease-up plan at one building was kept as lasting staff guidance.
2. Which source wins when two disagree. Recommend B.
Why B: at Western Slope 29 building notes differ from a company-wide answer. 22 are building exceptions (no pets at Courtyard and Nashua, a flat water and trash fee at Pomona Park); A throws them away, and C throws away those and more. The other 7 are money and screening lines that look old: a $27 or $50 application fee against the company's $40, income of 3 times rent against 2 times, a $500 pet deposit against $300. Letting every note win would put those 7 in front of renters; B keeps the 22 and holds back the 7.
3. Aliases (other names renters use for a home). Recommend A.
The side-effect replay further down: the alias changed the home for 12 real messages, all naming "2858 C 1/2 Rd". Nothing else moved.
Most Western Slope disagreements are a building differing from the company rule, which is normal. The risk is the 15 against the home record (bed and bath counts, floor, square feet), where the home record wins, and the 7 fee, deposit and screening lines covered by rule B. Against dated staff answers for one building: 0 at both customers.
| Measure | Western Slope | Situs |
|---|---|---|
| Distinct notes read | 82 | 43 |
| Facts pulled out | 440 | 189 |
| Public renter facts | 224 (189 distinct; the same line repeats on several homes) | 123 (115 distinct) |
| Staff-only, kept private | 19 | 1 |
| Not loaded: dated (price, availability, specials) | 74 | 10 |
| Not loaded: already held | 107 | 47 |
| Not loaded: home record or listing wins | 16 | 8 |
| Dropped (parcel numbers, accounting placeholders, investor copy) | 37 | 57 |
| Alias candidates | 30 | 7 |
| Harness verdict | RED one dated staff line kept | GREEN |
Planted defects, each must turn the run RED:
| Planted defect | Result |
|---|---|
| The $62.15 flat water, sewer and trash charge filed as staff-only | RED as required |
| "109 rents at $2,595, 405 and 409 at $2,650" filed as a lasting public fact | RED as required |
| "Try not to show Pomona after 4:30PM on a Weekday" made public | RED as required |
| A known disagreement (bath count) published with its conflict row deleted | RED as required |
| Re-run with nothing changed / one note edited / one note emptied | GREEN 0 model calls / 1 call, old facts retired / old facts retired |
Model: Claude Fable 5.1 on the subscription, 125 reads for both customers on the first run. Matching to the audit and the second reading: Claude Opus 5.5. Seen in the notes for the first time: Ember Estates now has a note written straight to Clara with showing guidance (kept staff-only), and about 30 buildings carry only a parcel number (dropped). One known miss: the trial filed the repair-request emergency line as staff-only because it was told never to put a phone number in a renter fact; the real feature would read that line from the company's settings. Also open: the trial kept named site contacts and their phone numbers as staff guidance, and our knowledge rules say personal contacts are never saved; the real feature would drop them.
Every inbound text (320), email (164) and guest card (85) from Oct 4 to Nov 3, plus Clara's 7 place searches, run through the existing building-name matchers twice: today's aliases, then with the candidates added in memory. Nothing was written.
| Where | Changed | Before → after |
|---|---|---|
| Inbound emails | 5 | no home → Ember Estates (all name "2858 C 1/2 Rd") |
| Guest cards | 4 | no home → Ember Estates (same address) |
| Clara's place searches | 3 | "no match, hand off" → Ember Estates |
| Anything else | 0 | no unexpected change |
Add "2858 C 1/2 Road" → Ember Estates by hand now? yes / hold. Recommend yes. Floor-plan names: hold until a message uses one.
Replaces: questionnaire questions whose answer is already typed in the notes: utilities and who pays (Pomona Park, Courtyard, Lincoln, 1240 Bunting), parking rules, no-pets buildings, income limits at the affordable buildings, building facts at Situs (year built, parking counts, laundry). The onboarding gap list shrinks before the client sees it.
Shape: a new capability, so one company setting, default off. The PMS layer fills a neutral "property free text" slot, so another PMS fills the same slot. Each fact carries its source note and a fingerprint of the note's text; when the note changes or empties, its facts are retired. Disagreements land as rows on the customer's knowledge-coverage page. No approve or merge screen.
| Rung | What proves it | Status |
|---|---|---|
| Read-only replay of real notes | This trial: both customers, audit scored, 4 planted defects RED | done |
| Willows live run | A note on the Willows record; a test renter asks by text and email; Clara answers the fact and never says the staff line | next |
| Sandbox company | Same, in each customer shape | after Willows |
| Turn on | You, per company | your call |
| Date | What | Status |
|---|---|---|
| 2026-11-03 | Local trial and harness on both customers' notes, fresh read-only pull; alias side-effect replay; no code in the product, nothing in CI | Proposed — pending review |
| Counts as proof | Does not count |
|---|---|
| A delivered email event (timestamp, message id) at the real recipient | A config resolver saying who the recipient would be |
| A real call over the deployed prod path, call id and verdict cited | Unit tests or single-turn evals: they never prove what Clara says (the 2026-08-19 application-link incident shipped green on both) |
| A fresh guest card created after the deploy getting its first email | An existing card only: it missed the race that dropped brand-new cards (2026-09-21) |
| A lead in the client's own shape (single-family, no unit, scattered homes) | A Willows or Camellia pass for a client shaped differently |
A direct read of both knowledge layers plus knowledge:verify-live | A gold-set grade: proof of content quality, never proof the live record has the answers |
| A check with a planted-defect control that goes red, derived independently of the checker | A check with no control, or one sharing the subject's parser (two "engine defects" on 2026-09-20 were grader errors) |
A prod_evidence permalink on the go-live tracker row | "Merged". The tracker shows merged-without-evidence as untested |
Before turn-on, the team plays prospects end to end with every channel live: "we have to do real dry runs where we simulate that we're prospects. We're just not gonna do it with real people who submit through AppFolio yet." (Fede, 2026-09-13)
| Org | Use for |
|---|---|
| The Willows (JP&Co AppFolio property 45, its own AppFolio portfolio) | Every AppFolio write; single-property shapes; household and identity proofs with real cards and applications |
| Fairhaven Residential (test) | Default centralized test company; company-level ring lists; new routing before any client |
| The 70-home Western Slope mirror org | Scattered-site and person-first proofs, first (Fede, 2026-09-21); Willows second |
No session creates another test org. Test orgs must reproduce customer issues; no test-only shortcuts in a proof.
docs/runbooks/real-path-e2e.md)Voice pre-PR: /fastlane (throwaway clone of the prod agent, real call, deleted after)
proof: /robocall after merge; cite call id + verdict (no pre-merge voice lane)
Email proof: scripts/email-stress/run.ts with STRESS_TRANSPORT=ses (or gmail), post-deploy;
cite message id + a clean Sentry window. sqs transport = smoke only. No --cleanup.
SMS pre-merge: ./scripts/claim-preview.sh --status first; preview number; --release when done;
deploy the preview inbound-processor Lambda for src/lib-only diffs
Cards /guest-card-regression (reply quality) or /household-regress (identity),
one canonical corpus at ~/.claude/guest-card-corpus; never re-mine
"Turning it on YOLO immediately is not a good strategy… a week where it's human in the loop… then after that week if it's good we turn it on fully."
Fede, 2026-09-22, session 010
| Stage | What happens | Switches | Exit |
|---|---|---|---|
| 0 · Connected and dark | Mailbox, calendar and AppFolio connected; everything is read and recorded. Clara does not proactively act on records from the client's portfolio (a new guest card or inquiry is recorded, not answered), and the client's public number is not forwarded yet. Everything else works with no gates: the line answers, and texts, confirmations, reminders and follow-ups go to whoever reaches it. Dry runs as prospects happen here. | Company live switch off. Client forwarding off. | Section 2 complete with proof. |
| 1 · Supervised, about a week | Client turns on forwarding; every destination is proven by a real call that day. Every composed email to a prospect is held and posted to the client's Slack channel for PropFlow staff to ship, edit or hold. Tour confirmations are never held. Guest cards: reply only to cards AppFolio created by itself; cards staff type in by hand are left to staff. | Company live switch on. Review hold on. Client forwarding on. | See exit criteria below. Fede decides. |
| 2 · Fully on | Clara sends without review. Guest cards staff type in by hand are answered too, if the client wants (once that setting exists). | Review hold off. "Reply to guest cards staff type in by hand" on (planned). | Steady state. |
Known tension in Stage 1: the client's staff can answer before a held draft is approved. Those drafts are rejected, not sent.
| Restriction | Why | Removed at |
|---|---|---|
| Review hold on composed prospect emails | Quality unproven on this client's cards | Stage 2 |
| Reply only to guest cards AppFolio created by itself | A temporary ramp-up stage (Fede, 2026-09-22): "we can either reply to all guest cards or if they have some that are manual, like exclude those at the beginning." Today this is fixed code: the card's oldest activity-log row must be "Guest Card Received" by System. | Stage 2, through the planned company setting "Reply to guest cards staff type in by hand" (off during ramp-up). Not built. |
Proposed — pending review 2026-10-31 · first use: Situs Group leasing team · not sent
One email from Clara to the whole leasing team on go-live day: who she is, what she does, what to expect, and the three things she needs. Built from shipped copy and Fede's past edits, not new prose. To: everyone who works leads or gives tours. From and Reply-To: clara@propflowai.co, hello@ as a hidden BCC (Fede, 2026-10-30). Plain coworker note, signed "Clara".
Subject: Meet Clara, your AI assistant for Situs Group
Hi everyone,
I'm Clara, your AI assistant for Situs Group. I'm joining the leasing team to help with renters who ask about a home and to set up tours with you. Here's what I'll start doing and what to expect.
Any lead that reaches the inbox by email, from any listing site, gets a guest card in AppFolio written by me, so you don't have to type it in. Same for calls I take, including after hours and on weekends. Then I email them, text them, and keep following up for two weeks until they reply or book a tour.
If a renter asks something I don't know, I'll email you and ask instead of guessing. Just reply with the answer and I'll get back to them. I'll remember it for next time, so I won't ask you the same thing again. That's how I'll learn how you all work.
When I book a tour with you, it goes on your Google calendar and as a showing in AppFolio, assigned to you, and I'll let you know. I remind the renter before the tour. Afterward, I'll ask you how it went and add your notes to the guest card. Virtual tours are on Zoom. Each tour gets its own link, on your calendar invite and in the renter's confirmation. You join from the invite, no login or app needed, and I take the notes from the recording. If you need to move a tour, just email me.
Everything I do, from notes to showings, is written to the guest card in AppFolio, so you can always see it there.
If you give tours, three things help me:
Reply any time. Go Broncos!
Clara
| Paragraph | Source |
|---|---|
| Opening | Fede's approved welcome opener, "your AI assistant for <company>" (Oct 25, staff-welcome-text.ts). Second sentence is the Oct 30 intro rewrite, word for word. |
| Guest cards | Fede's dictation. "Two weeks" is the shipped follow-up ladder (1 day, 2 days, 1 week, 2 weeks) and his Sep 24 email to Western Slope. |
| Not knowing | Shipped welcome line in Fede's words: "I'll ask you for help instead of guessing." Shipped staff-ask ending: "Just reply… and I'll get back to them." Remember-and-never-re-ask is coworker habit A (Fede, Oct 24: Clara never asks "remember this?"). |
| Tours | Host's own calendar (#23587); AppFolio showing assigned to the host (#24163); after-tour check-in text (#24225, text only, so the cell ask); virtual-tour notes from the recording (Oct 31). "Keep open time open": Oct 27 calendar audit, busy blocks were eating tour time. |
| Left out | Supervised, reviews, Slack, approvals; Spanish routing (not built); robots (Fede, Oct 30). |
Go-live is two switches: ours (the company live switch) and theirs (call forwarding). The rest are per-company settings. Each row was checked against the code on 2026-09-22. Settings are staff-only.
| Switch | What it does | Where set / visible | Default | Stage |
|---|---|---|---|---|
Company live (claraLive) | Holds every customer-facing email Clara would send for the company, and the first reply and follow-ups on portfolio leads. Team notices are never held. Inbound is always read and recorded. | Customer page switch; PATCH /api/admin/companies/<id>/clara-live | Off | On at 1 |
| Client call forwarding | Puts Clara on the client's public number. Voice and texting have no other gate. | The client's phone system (their step) | Off | On at 1 |
Review hold (reviewOutboundEmails) | Holds every composed prospect email for PropFlow staff review in the client's Slack channel. Requires live on. | Customer page switch (disabled unless live); PATCH …/review-outbound-emails | Off | On at 1, off at 2 |
| Reply to guest cards staff type in by hand | Planned. Lets Clara answer cards staff typed in. | Company setting (not built) | Off | On at 2 |
Lead source (leadSource) | email: any recognised lead relay; appfolio_guest_cards: AppFolio guest cards only | scripts/set-org-lead-source.ts; no UI yet | email | Setup |
Prospect record owner (prospectRecordOwner) | appfolio / yardi / propflow_crm. Under a PMS owner, listing emails attach to the PMS card instead of minting a lead. | …/prospect-record-owner; company, property override | Unset (legacy path) | Setup |
PM reminders (pm_action_reminders.enabled) | Reminder emails to the property manager ("new application to review"). Turning on names the recipient. | …/pm-action-reminders | Off | Only if the client asks |
Ring lists (ring_list.leasing, .maintenance, .catch_all) | People rung in order for each caller need, 1 to 4 people. Catch-all beats the older bare office number. | scripts/set-ring-list.ts --role …; company, group or property | None (not rung) | Setup |
Maintenance route (maintenance.intake_route) | Clara takes it, or forward to the client's call center (optional menu digit pressed by Twilio) | Registry setting; menu leg via scripts/configure-maintenance-menu-bridge.ts | None | Setup |
Emergency on-call (emergency.route.residential, .commercial) | People rung for a life-safety call | Registry setting | None (falls back to the property emergency phone) | Built dark; no client configured |
Answer mode (human_handoff.acceptMode) | answer = plain forward; press1 = staff press a key; auto = voicemail detection | scripts/set-human-handoff.ts --accept-mode; company only | answer | Setup |
Text on ring (human_handoff.text_on_ring) | Texts the staff phone as it rings. Off because the callback path is not built. | scripts/set-text-on-ring.ts | Off | Leave off |
Office hours / tour hours (office_hours, tour.hours) | Reception hours vs tour-booking hours; tour hours fall back to office hours | Company, property override | Tours follow office hours | Setup |
Application link mode (leasing.applicationLinkMode) | fixed_url or pms_generated (AppFolio sends the application) | Company only | fixed_url | Setup |
PMS write-back mode (pmsSideEffectMode) | Internal cutover of the write-back dispatcher: shadow logs only, apply writes. Today's inline write-back stays live meanwhile. | …/pms-side-effect-mode | shadow | Engineering cutover, not a go-live step |
The customer page also carries a read-only go-live checklist (GET /api/admin/companies/<id>/go-live-checklist: portfolio connected, escalation owners, email identity, phone line, calendar, mailbox reading, inbox, billing). It never blocks the switch; section 2 is the full list. Removed for good, never re-add: the email shadow switch (2026-09-17), texts delivered through AppFolio (2026-09-20), the per-property mailbox toggle (2026-09-15), the "book on people's calendars" flag (2026-09-16).
One line each: what happened → the rule now. Most costly first in each group.
attachPhoneLine(), not a re-POST.The history behind the rules above, condensed. Add new entries at the bottom of the right subsection, dated. When a decision is superseded, say by what.
situsgroup.appfolio.com: 5 h 39 min wall clock, about 24 agent-hours; a re-pull with the toolkit took 1 h 35 min. 17% of effort was noise, almost all from records captured with no post-condition.| Decision | Outcome |
|---|---|
| D8 · One AppFolio login per client | Decided 2026-09-08: one Clara login per client, added by the client. |
| D4 · In-app review | Built: the in-product review page Western Slope used on 2026-09-15. |
| D5 · Documents | Superseded 2026-09-15: the client uploads documents into the knowledge base; not taken by email. |
| D3 · What loads into Clara | Superseded by the knowledge flow in section 4 (consolidation, layers, held-out items). |
| D1 · Where the playbook lives; D2 · pull scope; D6 · data-use clause; D7 · "overnight" promise; D9 · live data before documents | No ruling recorded. Treat as proposals. |
| Date | Fede's ruling | What it means |
|---|---|---|
| Sep 5 | Western Slope up fast on what we have; Situs can take longer | The playbook serves a fast simple client and a slow hard one |
| Sep 7 | "we should just call APIs" | Deterministic pull; browser robot only without an API |
| Sep 7 | Situs and Western Slope "are separate companies" | No cross-client knowledge, ever |
| Sep 7 | PropFlow sets the PMS in the back office | Never a client wizard question |
| Sep 8 | "we just collect free-form… when we inject it… we decide how we structure" | Clients answer in plain language; we structure |
| Sep 9 | "i never asked for a suggested link feature" | No merge or confirm buttons; the engine decides |
| Sep 11 | "I told you to do a full end to end QA" | A partial pass is not QA |
| Sep 11 | Clara never quotes income limits, decides eligibility, or states a blanket "no assistance animals" rule | Fair-housing items go to a person |
| Sep 12 | First-time bulk import is a different job from day-to-day polling | Separate code paths |
| Sep 15 | Questionnaire goes to hello@ first; client self-signs up and adds Clara in their AppFolio | Human in the loop, then autonomous |
| Sep 16 | 30-day import window by AppFolio's own date | Sync creates nothing older, but keeps updating what it has |
knowledge:verify-live fixed it.Western Slope answered all 22 review questions on Sep 15, and the apply did run: 18 company facts were written to the org node that day, application fee $40; hours were updated there again on Sep 18. The Sep 21 investigation read only the property row (8 old sections) and the review's "open" status, and concluded wrongly. The real gaps were one Ember Estates exception (written that night) and Redcliff having no property row. The $27 fee came from a scrape overwriting a verified field (#10572). Root cause: company knowledge lives on the org node, exceptions on the property node; a check that reads one of them, or trusts a status field, reports the wrong thing.
| Symptom | Root cause | Rule now |
|---|---|---|
| Clara said a lockbox-only home shows in person. | Home exceptions had nowhere to load; nothing compared live to approved. | Load every fact or refuse; verify live. |
| A test call got old draft hours after approval. | Write not propagated; stale field. | One hours setting, read back live after every write. |
| Evening and weekend tours refused. | Tour slots read reception hours. | Separate tour hours. |
| Staff tour emails stopped on the client's test day. | Staff notices were put behind the live switch. | The live switch holds prospect mail only. |
| "Staff email is on" for days, nothing received. | Evidence was a resolver answer. | A delivered event is the proof. |
| Client's delivery log empty for the whole onboarding. | Leftover shadow switch. | No shadow switches; deleted. |
| Team notices went to an engineer's smoke mailbox. | Setup test address left in place. | Every address is the client's before the first live call. |
| Tour notices for 69 of 70 homes reached nobody. | Recipients only per property. | Fall back to the company escalation contact. |
| 100 reminder emails in an hour. | Old records imported; reminder with no age cutoff. | 30-day window; reminders opt-in. |
| Repair callers handled by Clara, not the call center. | Recognition beat the route. | Intake route outranks recognition. |
| Every call on every line failed for two hours. | Empty dynamic voice field. | No empty fields; revert first. |
| A call reached Clara with no property context. | Company-scoped routing record short-circuited lookup. | Only property-scoped records short-circuit. |
| Invented "deposit is one month's rent". | Company sentence beat the listing. | Figures from the listing. |
| Mailbox connect failed three times. | No Full Access or Send As. | Grant and prove before connecting. |
| No lead email ever produced a guest card. | AppFolio's guest-card notification was off. | A named setup step at the client. |
| Nothing reached the team Slack channel. | No channel set, then renamed. | Register by permanent id. |
| A confirmed tour never reached the calendar. | Stale connection, silent failure. | Fail loudly; verify via the calendar API. |
| Wrong persona names; a repair note in a leasing email. | Personas shared one number; shared free-text note field. | One number per persona; no shared note field. |
| Twelve empty tour records. | An update path created placeholders. | An update never creates. |
| Nothing could be written back to AppFolio. | Robot account drafted, not applied; no mapping. | Robot login proven; every front door mapped. |
PRs behind these rules: 7919, 7962, 8007, 8043, 8060, 8314, 8375, 8378, 8458, 8553, 8606, 8638, 8704, 8726, 8750, 8844, 8861, 8882, 8893, 8900, 8912, 8913, 8923, 8927, 8934, 8958, 8962, 8964, 8968, 8969, 8970, 8973, 8977, 8978, 8979, 8980, 8986, 9013, 9031, 9036, 9046, 9047, 9098, 9103, 9105, 9113, 9135, 9137, 9139, 9140, 9144, 9148, 9155.
~/situs-data, shared AppFolio login with JP&Co at the time.POST /api/onboarding/pms/appfolio/import) needs API credentials. A prod scan found no Situs records at all. Situs waits on AppFolio API access or a browser-based import. Update 2026-09-29: Situs Group connected through the standard connect step today (52 buildings); see the retrospective in section 9.Documented at the Willows, headless: guest card → Rental Application → Send Rental Application. The form needs a specific unit or campaign (a bare property 400s) and an email even for SMS. It posts to /guest_cards/{id}/email_rental_application keyed on AppFolio's live unit id, which is not PropFlow's id: any automation must re-resolve it at send time or it can send the wrong home. A successful send is a quiet timeline event, never a staff email (2026-09-19).
TL;DR: Western Slope's import hit 6 real mistakes over 10 days. Four of them cannot happen again (the code now prevents them). One was repeated at Situs today: the sync was connected without the rate-limit protections turned on, and AppFolio started refusing calls within minutes. One is still unfixed at both customers (the property list never refreshes after import).
Smaller ones: 2.5 baths quoted as 3 (136 units, fixed urgently Sep 25), two people split into duplicate records by the sync (fixed Sep 24), a synced application fee overwrote a verified one, duplicate prospect rows from two guest cards fighting over one person (partly fixed, two issues still open).
Recommendation: make the rate-limit switches and request budget part of the connect step (automatic, no human press) and make "residential only" an engine rule at import. Those two would have removed both of today's repeats.
| Old | Superseded by |
|---|---|
| "A forwarded main line never loops" (2026-09-19) | A forwarded number is never a valid destination (Fede, 2026-09-22: "I was wrong, so we should remove that") |
| Office main line as the catch-all (#10586, 2026-09-21) | A people-based catch-all ring list; the office line only when it does not forward to Clara (2026-09-22) |
| Catch-all open decision: take a message vs ring a PM on-call list (2026-09-22) | Still open for Fede. Today: take a message unless a catch-all ring list is set |
| Live switch holds only portfolio leads (2026-09-11) | Holds every customer-facing email; team mail never held (2026-09-16) |
| Guest-card notes: outcomes only, one short sentence | One note per turn, appended, never edited (2026-09-22, "just for now") |
| No follow-ups for guest-card leads | Guest-card leads get the full follow-up cadence (2026-09-20) |
| "Knowledge reviewed" = client approved the file | Both layers read back and knowledge:verify-live green (2026-09-16, corrected 2026-09-22) |
| Press-1 accept as the default (2026-09-20) | Plain forward default (2026-09-21, #10567); voicemail-detection default still open (#10835) |
| Text-on-ring on by default | Off by default; callback path not built (2026-09-20) |
| Application link mode per property | Company level (2026-09-19) |
| Apply step writes to the anchor property (#8650) | Company layer plus the named home (2026-09-15) |
| Western Slope AppFolio read-only | Real writes through the same robot as every client |
Fede's words, 2026-09-22, session 010 (the brief for this rewrite) ·
mining notes from session 010: phone lines, knowledge, email and turn-on, setup and testing (session memory files, PR history 2026-09-08 to 22, and the pages below) ·
code on origin/main at f7783a39cd (2026-09-22): src/lib/domain/portfolio/registry/keys.ts, src/lib/domain/organizations/clara-live.ts, src/app/api/admin/companies/[id]/*, src/lib/domain/pms/side-effects/mode.ts, src/lib/domain/leasing/guest-card-reply-eligibility.ts, scripts/set-org-lead-source.ts ·
docs/runbooks/real-path-e2e.md ·
PRs #8650, #8950, #10423, #10567, #10572, #10712, #10795, #10924, #10926 (merged); #10835, #10865, #10932 (open at time of writing) ·
Western Slope go-live tracker ·
Western Slope issue list ·
Phone line and hand-off architecture ·
Gera's portfolio architecture ·
Western Slope knowledge gold set ·
Situs Group initiative hub ·
~/situs-data/onboarding/ (playbook audit, UX research, question bank) ·
~/.claude/propflow-vision-2026-08.txt