05 · Orchestration
From a listing page to a signed deal — without a single re-introduction.
Brokher.com already exists. Proassistly already exists. This page defines the choreography that lets Zettlein pick up the visitor mid-scroll, inherit everything Brokher knows, act inside Proassistly on their behalf, and hand the thread back — with full context intact on every surface.
A · The handoff problem
Three systems, one continuous transaction.
Brokher.com
Discovery surface
Public, SEO, anonymous
Zettlein
Conversation surface
Stateful, multilingual
Proassistly
System of record
Auth, ledger, workflow
Losing context happens at three seams: anonymous → identified, conversation → transaction, and agent → human operator. The orchestration below is designed so no seam ever asks the user to repeat themselves.
B · The context envelope
One signed payload that every surface can read.
When Brokher hands a visitor to Zettlein, it does not pass a URL. It passes a signed Context Envelope — a short-lived JWT + JSON blob that captures who, where, what and why. Zettlein hydrates its session from it; Proassistly trusts it as a first-party claim.
┌───────────────────────── context envelope (JWT, 10 min TTL) ─────────────────────────┐
│ sub : anon:visitor-8f1c… | user:pa_01HK… (upgrades in-place on sign-in) │
│ tenant : kh-phnompenh │
│ locale : km-KH fallback: en │
│ surface : brokher.com route: /listing/BKK1-2BR-riverside │
│ intent : buyer.inquire | seller.list | investor.brief | landlord.rent │
│ subject_ref : listing:lst_01HK7Z… (or agent:…, project:…, none) │
│ signals : { budget_hint, viewed_ids[8], time_on_page, saved_search_id } │
│ consent : { pii:false, comms:false, marketing:false } │
│ resume_token : zt_res_9c4a… ← lets any surface reopen this exact thread │
│ sig (HS256, Proassistly-issued, verified by Zettlein and by any embedded widget) │
└────────────────────────────────────────────────────────────────────────────────────────┘Identity ladder
anon → known → verified. The sub upgrades in-place. No thread is ever orphaned when the visitor signs in — the same resume_token keeps working.Subject binding
Consent-scoped
consent.piiflips true. Guardrails read this flag, not the prompt.C · The choreography
Twelve steps from hover to signature.
| # | Actor | Action | What actually moves |
|---|---|---|---|
| 01 | Brokher.com | Mints envelope | On listing view, calls POST /rpc/v1/session.mint on Proassistly with anon cookie + page context. Receives JWT + resume_token. |
| 02 | Brokher.com | Boots Zettlein widget | <script src='zettlein.js' data-envelope='…'/> mounts a collapsed launcher. Zero re-render of the page. |
| 03 | Visitor | Opens Zettlein | Widget expands. Zettlein greets in envelope.locale, referencing subject_ref by name: 'The BKK1 2BR — want a quick tour of the numbers?' |
| 04 | Zettlein | Hydrates memory | Calls tools.read.listing.get, tools.read.market.brief, tools.read.saved_search.get. Reads only — no PII collected yet. |
| 05 | Visitor | Asks to see it | Zettlein proposes 3 slots. Needs contact → asks consent inline. On accept, consent.pii flips; envelope re-signed. |
| 06 | Zettlein | Writes to Proassistly | tools.write.lead.upsert + tools.write.viewing.request. Proassistly returns lead_id and viewing_id — both stitched to sub. |
| 07 | Proassistly | Emits events | lead.created, viewing.requested → CRM inbox for agent, calendar hold, SMS/Telegram OTP. Brokher's read-model updates via projection. |
| 08 | Visitor | Leaves the tab | Nothing lost. resume_token persists in httpOnly cookie + email magic link. Thread state saved server-side on Proassistly. |
| 09 | Visitor | Returns via email link | Any surface — Brokher, Zettlein standalone, Proassistly buyer portal — accepts the resume_token and rehydrates the exact turn. |
| 10 | Zettlein | Advances the deal | tools.write.offer.draft → tools.write.reservation.create. Zettlein assembles the reservation agreement from Proassistly's legal DSL. |
| 11 | Proassistly | Escrow + signature | Escrow ledger opens; ABA/Wing payment intent issued. DocuSign-equivalent sends. Zettlein watches doc.signed event. |
| 12 | Zettlein → Human | Warm handoff | Agent inbox receives full transcript, envelope history, action log. Zettlein stays in the thread as co-pilot, not replaced. |
D · Sequence
What the wire looks like.
Visitor Brokher.com Zettlein Runtime Proassistly RPC │ │ │ │ │─── view ──────▶│ │ │ │ │── session.mint ────────────────────────────▶ │ │ │◀────── envelope (JWT + resume_token) ────────│ │ │── boot widget(envelope) ──▶│ │ │◀── greeting ────────────────────────────── │ │ │─── "book a viewing" ───────────────────────▶│ │ │ │── read.listing.get ─▶│ │ │◀──── listing DTO ────│ │ │── read.availability ─▶│ │ │◀──── slots ──────────│ │◀── proposes 3 slots ────────────────────────│ │ │─── "yes, +855 12…" ────────────────────────▶│ │ │ │── write.lead.upsert ─▶│ │ │── write.viewing.req ─▶│ │ │◀── ids + events ─────│ │◀── confirmed, calendar hold ────────────────│ │ │ │ │ │ (closes tab) │ thread persisted ▲ │ │ │ │─── clicks email link (resume_token) ─────────────────────────▶│ │ │◀── redirect to brokher.com/thread/… ─────────│ │ │── boot widget(resume) ────▶│ │ │◀── "welcome back, the viewing is Thu 3pm — want to draft an offer?"
E · RPC contract
Zettlein never touches the DB. Proassistly exposes /rpc/v1.
Read plane — idempotent, cacheable
Projection reads
session.mint·session.resumeread.listing.get·read.listing.searchread.market.brief·read.comparablesread.availability.get·read.saved_search.getread.thread.get·read.legal.template.get
Write plane — audited, event-sourced
Guarded by consent + role
write.lead.upsert·write.consent.grantwrite.viewing.request·write.message.sendwrite.offer.draft·write.offer.submitwrite.reservation.create·write.escrow.openwrite.document.assemble·write.signature.request
Every write returns a command_id. Zettlein stores it on the turn so retries are safe. Every write emits a domain event so Brokher's read-model and Zettlein's RAG index stay in lockstep.
F · Continuity guarantees
The four rules that make context untouchable.
01
One thread, many surfaces
thread_id is issued by Proassistly at session.mintand travels with the envelope. Brokher, Zettlein and the Proassistly portal all render the same thread — never a copy.02
State on the server, not the tab
03
Anon → identified is a merge, not a restart
subinto the user account. Lead, viewings, offers and transcripts follow.04
Human takeover keeps the agent alive
G · Failure modes we design against
Where handoffs usually die — and how this one doesn't.
| Failure | Where it strikes | Mitigation |
|---|---|---|
| Envelope expiry mid-chat | Long viewings, mobile sleep | Silent refresh via resume_token; user never sees a login prompt. |
| Duplicate lead on re-entry | Anon → known merge race | write.lead.upsert is idempotent on (sub, subject_ref). |
| Zettlein hallucinated price | RAG stale, projection lag | Prices are never in prompt — always fetched fresh via read.listing.get at answer time. |
| Agent responds in CRM, visitor doesn't see it | Split inbox | Agent messages travel through the same thread_id — pushed into Zettlein UI as an actor turn. |
| Payment intent orphaned | Escrow opened, user drops | escrow.opened event triggers reminder sequence across email + Telegram, resumable to the same thread. |
H · Rollout
Ship the orchestration in four surgical drops.
Drop 1
Envelope + widget
2 weeks
session.mint, JWT signing, embed script on brokher.com/listing/*. Zettlein greets, no writes yet.Drop 2
Read plane
3 weeks
read.* RPCs wired. Zettlein can answer factually with zero hallucination surface on price and availability.Drop 3
Write plane — soft
3 weeks
lead.upsert, viewing.request,message.send. Human agent still closes the deal.Drop 4
Write plane — deep
6 weeks
offer.*, reservation.*, escrow.*,signature.*. Zettlein now walks a buyer to signature under agent supervision.One sentence to remember.
Brokher owns discovery, Proassistly owns truth, and Zettlein owns the thread that carries the visitor from the first hover to the last signature — without ever asking them where they left off.