Nine roles on the critical path, deliberately unequal. Only the persona agents talk to people, and they also drive: each one rules the room's goals and sends what other participants are owed, in the same turn as its reply. DistilMemAg records facts in the background; and the quiet-chain and back-office roles never appear in a live conversation at all. Two readers sit outside this cast — the asset agents below — because they judge nothing about a deal: they distil one file or one page, and are handed the room only to disambiguate a name.
Bring a conversation to Z adds AddConvAG
(add-conversation) to the ops catalog. It is talent-side intake, not a fifteenth
room role: it never sits in the deal room and never talks to the brand.
Every participant in a room has their own persona agent — the one voice they ever hear. It is the same kind of agent in every seat; what differs is the instructions it carries and who it faces.
The host-facing persona's first job is to understand the person — not just their commercial rules but enough about them to represent them well and to talk to them like someone who knows them. Later it delivers outcomes: terms have been negotiated, here is what they are, do you want these terms?
The welcome screen does not use that host persona. It uses
routerAG, listed in the admin agents page as
router-ag. See Welcome.
The visitor-facing persona negotiates. It reads the whole visible memory,
including host.mandate and pendingPrincipalDecisions, plus the live
DEAL STAGE block from the offers row. It asks for whatever the visitor
has not supplied, refuses terms that break a stated rule, and settles when a
mandate or principal instruction covers the decision. If no mandate covers a
price or yes-no, it says it is checking with the principal and collects what
is missing — it never names the floor or that a mandate system exists. What
it settles in chat is negotiation, not a booking, and it says so at the
moment of closing. It is strictly forbidden by code directives from
declaring an engagement booked, official, or signed unless the DEAL STAGE
block shows a BOOKED stage.
Persona agents see the visible memory plus the live DEAL STAGE block. They
record no facts — that is the background memory writer's job — and they are
grounded hard: the conversation, the memory, the DEAL STAGE block, and the
dispatch record are the only things that exist for them. They confirm nothing
on their own authority; a booking is confirmed only when the DEAL STAGE block
shows a BOOKED stage.
What a persona does act on is the negotiation itself. In the same turn as its reply it can:
Before anything goes to the other side, it still asks once whether there is anything to add. Once that is answered, the message goes out in that same turn, with any missing terms named as open questions rather than held back. An answer another agent asked for about the counterparty in this room is a message too: once the principal gives it, the persona sends it on.
The one thing a persona can do beyond talking is read what the person put in front of it. That is perception, not action: it cannot go looking for anything nobody handed it, it has no inbox, and it still has no signing authority. If a page or file cannot be read it must say so — "I've reviewed the brief" is false by construction unless the brief actually reached the model.
A file attached to a message arrives as a native input. A link is read by
scrapePublicUrl, which returns the page's readable text: it checks the URL is
public first — no localhost, private addresses, or embedded credentials — then
reads the page with Gemini URL Context on google/gemini-3.1-flash-lite,
and falls back to a bounded direct fetch. It fails closed: if the provider does
not report having fetched that URL, the link is unreadable rather than described
from something else. Google Search is deliberately not part of it, so an
unindexed brief is never answered from whatever the web says about the brand
instead — see Design Decisions.
A persona does not have to ask for a link, either. Any turn carrying a message — web chat or an inbound email reply — reads up to three links found in its text into room assets before the planner runs, so the reply to that very message can already use the page. Scripted rooms skip it: a replay must not call an external page reader.
Attachments live in media storage and travel through the transcript as a URL, so a conversation does not carry megabytes of bytes around; the bytes are pulled back at call time. Text-like files are reduced to their readable content in the browser before they are ever sent.
A file or link shared in a room becomes an immutable room asset, and two
agents read it. Both run on google/gemini-3-flash. A roster import is the
exception: the page read itself writes the profile on Gemini 3.1 Flash Lite,
the account summary uses that same lighter model, and the second distillation
does not run. Adding someone by hand still writes the summary on Gemini 3 Flash.
AssetAg distils the asset once, into a fixed intelligence layer — what it is, what it is for, its important details, and what is ambiguous or missing. The asset is the only evidence: the room's memory and transcript are supplied purely to disambiguate a name or a term, and anything a reader could not derive from the asset alone is audited out before it is stored. A link the reader could not open is stored as a failed asset rather than dropped, so the planner can tell the person their page was not accessible instead of silently knowing nothing about it.
AssetReadAg answers one focused question against the original asset later. It is deliberately given no memory and no transcript: a read is an asset-only question, and handing it the conversation lets it answer from chat instead of from the file.
The speaking agent, and the driver of its conversation. After a message is
stored it reads the whole visible room document — everything except
plannerNotes, flags, and other agents' plans — plus the roster, the room's
goals, the live DEAL STAGE block, the dispatch record, asset intelligence,
and clock, then replies and takes the actions described above. Host, visitor, onboarding, and campaign personas share
the same voice, memory contract, and deal-stage vocabulary; the visitor
persona also runs the mandate check itself. The stage table lives in
Design Decisions.
planner-distil-mem)The background memory writer. It starts at turn start and
runs as a fire-and-forget HTTP sub-request (/api/z-agent/distil/callback) on a deep reasoning model
(spacexai/grok-4.7). It does not delay the active persona's first token or
hold the reply stream open after streaming finishes. It used to be the
planner that decided goals and pushes; those decisions now belong to the
personas (see Design Decisions), and this
role only records.
It records:
offers.<key>.offerId only.It never touches what the personas own: the goals, each persona's plan, and
the principal's one-time answers. It never sends a message. Code enforces
this in live rooms: anything Distil writes to those branches is dropped, and
any push or room action it returns is ignored. Only scripted replays still
apply recorded planner beats. Abandoned of a
live new-offer goal is still not a no-op: code maps it to reject-offer and
closes the written row (ZLY-1935); met of new-offer still mints via
Offer-Gen — whichever agent ruled it.
It sees the full context: the memory document, roster, declared goals, live
physical-layer facts, the dispatch record of actually delivered messages, and the
recent transcript. Anything a visitor-facing persona must not say belongs under
plannerNotes, or is worded in the host branch as a boundary, not a floor.
Chat turns Distil by default. The onboarding interview (/onboarding, and its talent, brand and agency variants) does not run the background memory pass after each message, so guest turns stay cheap; the persona marks the setup goal in its own reply, code saves typed names, and one promotion pass runs at sign-in. Every other surface — Personalize, deal rooms, email, SMS — Distils beside the reply. Distillation always runs in the background: the reply stream closes once persona tokens finish, and a chat turn never waits for it.
awaitDistil: true)Callers that immediately assert or inspect room memory upon stream completion — such as Test agent (demo-simulation.ts), scenario replays (zreplay), and CLI test scripts — pass awaitDistil: true to run and await distillation in-process rather than dispatching it to an external HTTP invocation.
Rooms are permanent, so a seed at bind goes stale the next time the Arvist writes. Bind itself copies durable memory, or the home host branch when that document is newer. AccUpdate is the inbound counterpart: before the planner runs, if a bound account's durable memory is newer than the last merge into this room, AccUpdate copies standing knowledge into that participant's branch of room memory — who they are, their rules, how they like to be spoken to — and the planner waits behind the write.
It is not a second planner. It does not steer conversations, touch goals, or reorganise the document. It may only write under the participant's own key; reserved branches and everyone else's knowledge are discarded by the mechanism, not by instruction. On conflict the account wins, because durable memory is the curated long-term record. Room-only facts the account document does not mention stay.
A successful merge is announced in the transcript as a system line naming the account and the paths written, so the planner, the guard and the Arvist can see where that knowledge came from. The playground shows the same event as a banner with the change list; the product panes ignore it, so the person in the conversation never sees it.
The planner is told to treat that content as verified standing knowledge from previous rooms — never to delete or quarantine it as unsourced just because this sitting's messages did not mention it.
The auditor. Each agent acts on its own judgement, and the memory writer only records, which leaves a structural blind spot: the last agent message of every sitting is never reviewed by anyone. If the conversation goes quiet after the agent's reply — exactly what happens when a person says "great, do it" and walks away — whatever that reply promised goes unchecked. ZGuard closes the gap: a few minutes after a room's last exchange, it reads the whole room — every pane's recent conversation, the full memory, and the dispatch record, the system's ground-truth list of messages actually delivered — and verifies that the record holds up.
What it checks: claims of completion that nothing supports, memory notes
saying something "is being delivered" with no matching dispatch, participants
left waiting for a promised message that never went out, deal stage mismatches
(an agent declaring a booking while the live offer block shows no BOOKED
stage — a relay of the principal's chat instruction is not a mismatch),
goal statuses that contradict the transcripts. When it finds a failure it
makes the smallest repair: correct the false note, clear the stale
instruction, and — only when someone is genuinely owed an undelivered
message or an explicit walk-back of an erroneous booking claim — push it
through the same mechanism the planner uses. There is no quiet-window or
word-overlap filter on those pushes: if a participant is owed an update,
Guard says it, and the prompts keep the wording concise.
Guard never writes memory beside Distil. When the quiet-room callback fires, it waits for Distil's lease, claims it, then audits. If Distil is still running after a full lease, Guard re-arms instead of racing it.
Its expected answer, most of the time, is "healthy — no action". The verdict of every run is recorded and shown to operators, so a room's health is visible even when nothing needed fixing. And it deliberately stays in its lane: no strategy changes, no second-guessing judgement calls — a proofreader with a red pen, not a co-author.
Rooms are permanent — a host's home room and every visitor's deal room stay open for as long as the relationship does — but a sitting inside one still ends. On a live home room, Arvist runs after Distil for the host so Update Agent commits standing preferences immediately (ZLY-1897). On other rooms — and as a catch-up if that per-turn home run fails — a few minutes after the room goes quiet, on the same debounced signal ZGuard uses and right after ZGuard's own pass, the Arvist decides what the system keeps about each participant who took part, beyond this sitting. It maintains one durable memory document per account — who this person is, their standing rules, how they like to be spoken to, and the deals they have closed — which seeds every room that participant is ever bound to, so the planner never starts from zero. A new deal room can also seed the host branch from the home room when that document is newer than durable, so a z-link opened in the next second still sees the update.
The Arvist is deliberately selective where the planner is generous: the planner records everything that might matter within a room; the Arvist keeps only what will still be true and useful months later. What it drops is gone — this is the only document that survives the room — so a learning left out of it is a learning the system never had.
It is also shown, at call time, when each standing leaf of that document last changed. Those dates are written by code when a value actually changes, not by the Arvist, and they are not part of the document — see When a standing fact was recorded. A floor that has stood since March is a different judgement from a floor the account just moved. The planner does not see those dates today; putting a human look on extremely old facts is future work.
The bridge from understanding to record. When the planner rules a negotiation concluded, Offer-Gen reads the room and extracts the exact agreed terms — deliverables, amounts, timeline, usage boundaries — into a formal draft offer in the physical layer. Precision beats completeness: every field it fills must be a term that was actually agreed, and anything not discussed stays empty rather than being padded with an assumption.
The memory then holds only a reference to the offer, never a copy of its terms, so the document of record cannot drift out of sync with the memory's paraphrase of it. Minting the row unlocks the conversation Offer tab. Both sides Approve on that document in the product; brand pay-in is Send Payment after talent Approve. Offer-Gen never takes a card or walks Connect.
Offer-Gen's counterpart for a negotiation that kept moving. An offer is written once, but the conversation around it does not stop — a price gets raised, a deliverable added — and a host who is told the news must never open an offer that still shows the old terms. So whenever a push message is about to reach the host and the room already references an offer, Offer-Update re-extracts the terms as they stand now, against the same strict schema Offer-Gen used, and brings the live offer row up to date before the host's persona speaks.
It is deliberately conservative in three ways. It diffs before it writes:
fields the negotiation never touched keep their stored values, and an
extraction identical to the row skips the write entirely. It only touches
offers still in DRAFT or APPROVED. Once talent has booked (ACCEPTED and
later), or the row is already COUNTERED / REJECTED via the respond API,
the terms belong to the parties and it refuses without a model call. A
material rewrite of an APPROVED row clears brand_approved_at
(BRAND_APPROVAL_CLEARED) so a one-sided brand yes cannot survive new terms
(ZLY-1932). And an offer minted by the very run that is pushing is left
alone — it was just extracted from the same state and cannot be stale.
An Offer-tab Counter, Reject, or Add click does not write the row on the click and does not block Offer-Update. A counter is a chat line first: Z asks last-look, and only after the answer the persona records it through a post-reply action, which moves the row to Countered through the same offers-system transition, attributed to the side that countered. The other side is always told about the counter, even if the persona did not also send it a message in that reply. Distil still rewrites the row when the agent agrees the terms changed.
Like every back-office role, each invocation — including the refusals and the no-change skips — is recorded as a run with its cost, so there is always an answer to "why does this offer say $15,000 now".
Offer-Gen's next projection: the Offer is already the record, and AgreementAg turns that record into a lawyer-reviewable English draft. It never sees the room. The only input is the Offer's commercial fields — names, amount, currency, deliverables, usage, sharing — and it must not invent a missing term: no governing law, venue, indemnity, payment schedule, or exclusivity that the Offer did not already hold.
It runs whenever the Offer is minted or its negotiated terms change, and again if someone opens the agreement view while the draft is missing or stale. A fingerprint of those commercial fields decides whether the stored draft is still current; if the Offer changes mid-generation it retries once. A failed agreement run is recorded and must never roll back a valid Offer.
The application, not the model, adds the disclaimer and signature blocks. The draft is never described as signed, binding, or legally approved — those words belong to the parties, not to this agent.
The order matters more than it looks.
The persona answers from the whole visible document. Distil writes after the reply so first token is not stalled on the memory rewrite:
plannerNotes and flags
stripped) plus the roster, the live DEAL STAGE block, the dispatch
record, and clock.PlannerDistilMemAg is dispatched as a detached background sub-request
(/api/z-agent/distil/callback), running on spacexai/grok-4.7 to distill new facts.Most turns are reactive: a person writes, the system answers. But some things must not wait for the person to write — a deal came together, information they were waiting for arrived, the principal gave an instruction. For these, the persona speaking where it happened sends a message as part of its turn: who to tell, and the substance that must be conveyed.
The recipient's persona agent is then woken to deliver it in its own voice. The sender supplies the what — everything the recipient's agent needs, since the recipient may know nothing yet — and the recipient's agent supplies the how. The substance is always written from the recipient's point of view: participants do not know other conversations exist, so nothing that arrives ever refers to "the visitor's chat" — from their side, news simply arrives.
The host appears at the beginning and the end. Everything between is handled
without them — but nothing books them until the written offer reaches a
BOOKED stage.
This table is the security model in one place.
| Role | Sees a participant's words | Sees other conversations | Sees full memory | Can write memory |
|---|---|---|---|---|
| Persona agent | Their own participant only | Never | Yes — minus plannerNotes, flags, and other agents' plans | Goal rulings, its own plan, and the principal's one-time answers — never facts |
| PlannerDistilMemAg | Everyone's | Yes | Yes | Room memory — facts only, never goals or plans |
| AccUpdate | No | No | The room, plus that account's durable memory | Yes — that participant's branch only |
| ZGuard | Everyone's, when the room is quiet | Yes | Yes | Repairs only — room memory |
| Arvist | Home host after Distil; otherwise when a room goes quiet | Yes | Yes | Durable account memory only |
| Offer-Gen | Everyone's, when triggered | Yes | Yes | The formal offer only |
| Offer-Update | Everyone's, before a host push | Yes | Yes | The existing offer's terms only |
| AgreementAg | No — the stored Offer only | No | No | The agreement document only |
| AssetAg | Current conversation, to disambiguate a name | No | Yes, for disambiguation only | The asset's fixed intelligence only |
| AssetReadAg | No | No | No | No |
Two boundaries are enforced by the mechanism rather than by instructions:
plannerNotes and flags are stripped before any persona sees the document,
and each persona is shown only its own plan. Plans are never offered to the
person as memories and never carried into durable account memory.
The visitor persona is told not to reveal the host floor or that a mandate
system exists; that line is prompt-guarded. What Distil writes into
plannerNotes stays private.
The instructions each role follows live in the codebase, not in a room setting. The playground and ops dashboard still let an operator pick models; they do not edit prompts. A prompt change is a deploy, so every existing room — a host's home included — picks it up on the next turn. See Design Decisions.
On This Page
The castPersona agentsThe asset readersPersonaPlannerDistilMemAg (,[object Object],)Interview turns skip DistillationSynchronous Distillation for Scripts and Simulations (,[object Object],)AccUpdateZGuardArvistOffer-GenOffer-UpdateAgreementAgHow a turn worksWhen an agent reaches outThe full lifecycleWho can see whatPrompts are the code