The single AI-led account setup, default capabilities, roster inference, and memory promotion lifecycle
/onboarding is one account-level conversation with the agent. It does not
ask the visitor to select Talent, Brand, Agency, Bouncer, Scout, or Roster.
The visitor starts as a guest and signs in near the end.
The agent learns three things, in order, in its own words:
Then it asks whether they have any question before it moves on. That line is not one of the canned question types. It can still show the generic Proceed pill. A confirm ("is that right?") can show the canned pair, That's right / Let me fix something. See Canned chips. When they acknowledge, the persona marks the setup goal in its reply and the page moves on to the photo card and sign-up.
The landing page also opens three interviews chosen by who they are claiming
(ZLY-2026): /onboarding/talent, /onboarding/brand and
/onboarding/agency. Same chat, same research card, same photo card and
sign-up; only the questions and their order differ. Each has its own page:
Talent Onboarding,
Brand Onboarding and
Agency Onboarding.
Every account receives two capabilities:
Roster is conditional. At finalization, AI determines whether the transcript explicitly establishes that this account manages offers for other people, brands, teams, or properties. If yes, it enrolls Roster. It never infers a fixed user type.
See Capabilities, Seats, and Derived Role.
Onboarding creates or resumes one home room for the account-level agent:
host participantservice = agentaccount-setupmemory.onboardingconst room = await createZAgentRoom({
title: "Your agent",
kind: ROOM_KIND_HOME,
service: "agent",
goalConfig: [ONBOARDING_SETUP_GOAL],
memory: {
onboarding: {
service: "agent",
serviceRevision: randomUUID(),
status: "active",
setupStarted: false,
coverage: {},
},
},
});
There are no separate Bouncer, Scout, or Roster home rooms.
The areas live in packages/z-agent/srv/src/onboarding-questions.ts and are
injected into the persona's runtime instruction
(onboarding-instructions.ts). They describe what to learn, not a form:
| Flow | Areas, in order |
|---|---|
/onboarding (LANDING_INTERVIEW_QUESTIONS) | identity, sources, intent |
/onboarding/talent (TALENT_LANDING_INTERVIEW_QUESTIONS) | sources (handle and links), identity (only if research found no name), phone, dealTypes, smallestOffer, dreamBrands |
/onboarding/brand (BRAND_LANDING_INTERVIEW_QUESTIONS) | sources (website and socials), contact (the person, not the brand), idealTalent, formats, budget |
/onboarding/agency (AGENCY_LANDING_INTERVIEW_QUESTIONS) | sources (website and socials), agencyKind (only if research cannot tell), contact |
The agent asks one question at a time, in that order, and never stalls on a missing link. Completion is semantic: irrelevant or contradictory text is not evidence, and a short or informal answer still counts.
The talent, brand and agency interviews use the wording from the Question and Flow Framework (ZLY-2022). What code does for each of them (opening lines, names, the talent phone, whose links count, the account type) is on its page: Talent, Brand and Agency.
Interview turns skip the background memory pass. The persona rules the setup goal itself, in its own reply:
goals.account-setup met once the areas are answered and the
person has acknowledged the "any question before I move on?" lineserviceRevision is droppedonboarding.coverage is not written during the interview; the persona
reads the chat itselfWhen the goal is met the room view returns interviewReady: true and the
page leaves the chat for the photo card. Continue or skip there opens the
integrated authentication modal. A guest who reaches the message cap is asked
to sign in early (overMessageCap).
During the interview the agent only ever answers. It never messages on its own — no "Your agent reached out", no re-asking after a pause — and going quiet triggers nothing: the next question waits for the person. Reaching out becomes possible only after sign-up, on the dashboard.
Research runs only when the agent asks for it. In the onboarding chat the
persona has a researchTool instead of scrapePublicUrl, and calls it for
every new link. The call shows in the chat as a card: "Doing the
homework..." while the existing profile research runs, then the findings,
each line approved until the visitor presses Not me, then Done. The
chat input stays hidden while the card is open. Only what they confirm
reaches the profile and the agent. Pasting a link never starts research on
its own.
The full flow, the hidden input, what is saved and the edge cases are on Research Tool and Findings Card.
claimOnboardingRoom binds the guest host seat to the authenticated account.
Finalization then, inside the claim request:
bouncer and scout rows exist in account_service.Everything left is model work, so the request does not wait for it. Claim
returns first, then Next.js after() posts to
/api/z-agent/onboarding/promotion/callback. Posting from inside the claim
request kept that response open until Planner and Arvist finished. That
invocation:
roster only when that classification is true.Awaiting steps 3-6 in the claim request left the visitor on the live spinner for the length of two model calls, and could exhaust the route's time budget. Promotion carries a retryable lease, so a claim that arrives while an earlier attempt is still running is a no-op, and an attempt that died mid-flight is picked up by the next claim.
Roster can also be enabled later. My roster is always shown in the menu; an unenrolled account that opens it is asked the focused representation question and enrolled only after answering yes.
Arvist promotes the completed setup into one free-form
z_agent_object_memory document for the account. Identity, inbound
preferences, outbound goals, and roster context share that document.
There are no shared or services.<key> intelligent-memory branches. Exact
physical settings such as a Bouncer minimum offer remain in
account_service.settings.
When another room binds the account, the complete durable document seeds the
room's host branch — or the home room's host branch when that document is
newer (Update Agent Distil before the next Arvist). Visitor account memory
is never seeded into someone else's deal room. After the agent is live,
each Update Agent Distil runs Arvist for the host so a new preference is
durable before they test z-link.
The profile is thin right after onboarding. So in the weeks that follow, Z asks up to ten short questions, one at a time by email or SMS, and saves each answer on the account, most of them where matching reads them. The series only runs once the team has switched it on. See First 10.
| Area | File / endpoint |
|---|---|
| UI orchestration | packages/offers/client/src/app/components/onboarding/OnboardingPage.tsx |
| Routes (one per landing button) | apps/zooly-app/app/(pages)/onboarding/ (page.tsx, talent/, brand/, agency/), flow from the path in onboarding-flow.ts |
| Question areas | packages/z-agent/srv/src/onboarding-questions.ts |
| Lifecycle and roster inference | packages/z-agent/srv/src/onboarding.ts |
| Profile research agent | packages/z-agent/srv/src/profile-research.ts |
| Research tool and findings card | Research Tool and Findings Card |
| Profile corrections | packages/z-agent/srv/src/onboarding-profile-correction.ts |
| Prompt injection and coverage | packages/z-agent/srv/src/onboarding-instructions.ts |
| Durable promotion | packages/z-agent/srv/src/rooms.ts |
| Room endpoint | GET /api/z-agent/onboarding/room?service=agent |
| Chat endpoint | POST /api/z-agent/onboarding/rooms/[roomId]/chat |
| Research endpoint | POST /api/z-agent/onboarding/rooms/[roomId]/research |
| Claim endpoint | POST /api/z-agent/onboarding/rooms/[roomId]/claim |
| Promotion callback | POST /api/z-agent/onboarding/promotion/callback |