Zauthor tab (Playground)

Generate, upload, and push scripted scenarios from the browser, then open the room it creates — no terminal needed

The Z-Agent Author tab covers the whole scripted-scenario loop without leaving the browser: draft or upload a .zas script, push it under a handle, create a room from it, and either drive that room by hand or run the entire scenario automatically with its assertions. The same panel is still on the standalone Playground as a Zauthor tab next to DevCon.

Getting there

On the Z-Agent admin dashboard (/admin/z-agent), open the Author tab. The same panel is still on the standalone Playground (/z-agent/playground) as a Zauthor tab next to DevCon.

The tab needs no session beyond the one the Playground already has: it is admin-only, same as every other Playground endpoint, and it is only reachable at all when the server has Z_AGENT_MOCK_ENABLED=true. No bearer token — that exists for zpush, which has no browser session to carry.

Generate with AI

Two separate model calls, so you can review the people before paying for a script, and regenerate the script after a hand-edit without inventing new personas.

  • Deal sketch — a high-level description, not a checked-in scenario. Example: Nike offers 100K for three posts with six months of paid media. My floor is 250K.
  • Model (optional) — used for both calls. Left blank, the server default applies.

Generate briefs calls POST /api/z-agent/mock-tapes/briefs. That invents talent.md and brand.md in the same guide shape as packages/z-agent/srv/scripts/test-scenario/ — second-person sheets with floors, ceilings, deliverables, and a voice. Numbers from the sketch stay exact; names and texture are filled in. Each brief can be edited and downloaded.

Generate script / Regen script calls POST /api/z-agent/mock-tapes/author with those briefs (not a folder on disk). Outcome, turn count, and extra direction apply only to this second call. The draft lands in the Script box, which can also be edited and downloaded.

Open in Push & create a room pushes the script, creates the room, and opens it in a new browser tab — the same as the Push tab's Push & create room button. Account / real-room options still live on that tab if you need them first; use the tab itself rather than this shortcut.

If the script draft fails validation — say, an abandoned outcome that still minted an offer — the error is shown, and the invalid draft is loaded into the Script box anyway. It is usually one beat away from correct, and fixing it by hand there is cheaper than generating again.

Script

One shared textarea underneath, fed by whichever of these you used:

  • Generate with AI, above
  • Load an existing scenario on the Push tab — fills the box and handle from a checked-in .zas. Works on Vercel as well as locally; details under Push & create room below
  • Upload .zas — a plain file picker; reads the file's text into the box and sets the handle below from the filename
  • typing or pasting directly into the box

Download saves whatever is currently in the box as a .zas file, with no server call at all — useful if you only wanted the CLI-equivalent output to commit by hand.

Push & create room

Load an existing scenario lists every checked-in folder under packages/z-agent/srv/scripts/test-scenario/ that already ships a .zas (MaraVsDev, KenjiVsSolstice, and so on). Picking one fills the script box and the handle from that folder — the same as uploading the file by hand.

That picker works on a Vercel deploy, not only on a machine with the repo checked out. The scenario folder itself is not copied into the serverless function, so at build time the files are inlined into packages/z-agent/srv/src/mock/bundled-scenarios.generated.ts. Locally the server still prefers the files on disk, so an unsaved edit shows up without rebuilding. If you add a new scenario folder, run:

npm run bundle-scenarios --workspace @zooly/z-agent-srv

The zooly-app production build also runs that step, so a deploy picks up new folders even if it was skipped. A unit test fails when the generated copy is stale relative to the folder.

  • Handle — the id the tape is stored under, prefilled from the generated briefs, the uploaded filename, or the scenario you loaded, editable
  • Note — stored alongside the tape, for GET /api/z-agent/mock-tapes to show later
  • Talent account / Brand account — an account id or a search term, resolved server-side. Bind both to exercise offer minting; leave either blank and the negotiation still runs, but an @offer beat's effect is skipped rather than failing
  • Real room — creates a deal room instead of a playground one, so the conversation shows up in both accounts' own /dashboard/conversations instead of only the admin playground. Needs both accounts above bound; disabled while Guest brand is checked. An offer minted this way is still flagged isDemo and appears marked Demo in Offers & Deals — see Zreplay's --real-room
  • Leave brand an unclaimed guest — the brand seat gets a visitor cookie instead of a bound account, the same state a real z-link visitor is in before they log in. Every push and any offer-minting effect is composed but held rather than delivered. Disables the Brand account field and is disabled itself while Real room is checked — the two are mutually exclusive
  • Also send real wake-turn push emails — off by default, since a scripted room otherwise suppresses these so a replay does not mail a real person the same line every run. Persisted on the room itself, not a process-wide toggle, so it stays correct alongside every other request this server is handling

Push & create room does two calls in sequence:

  1. POST /api/z-agent/mock-tapes?id=<handle> — stores the script's source under the handle. Compiled first, so a malformed script is rejected here with its line number, not later as a confusing mid-conversation error.
  2. POST /api/z-agent/mock-tapes/<handle>/rooms — creates a room that reads its replies from that handle, with the accounts bound if you gave any, and with realRoom / guestBrand / sendEmails applied as checked.

On success, the new room opens in a new browser tab at /z-agent/playground?room=<id> (Talent view), so this Zauthor tab keeps the script, the public z-link, and Run full flow. An Open room button appears as well if you need another tab of the same room. The room is added to this Playground's room list without leaving Zauthor. A failed push closes the extra tab instead of navigating it.

Run full flow

The last section runs the whole scenario for you instead of leaving you to drive it — the same walk zreplay gives a scenario from the terminal, and the same assertions, reported in the browser.

It takes a room id, prefilled from the room the section above just created, but editable so you can point it at any scripted room — one made earlier by zpush --create-room, or one you replayed last week. An optional force ZGuard + Arvist checkbox exercises the quiet-room chain at the end, the CLI's --guard. ZGuard then kicks Arvist as a separate request; the replay result reports whether that kick was dispatched, not the promotion outcomes.

POST /api/z-agent/rooms/<id>/replay rewinds the room's mock cursors, sends every scripted human line through the real chat pipeline, adopts each planner push as it lands in the other conversation, and then checks:

  • every goal ended where the beats say it should
  • an offer exists if and only if the script mints one — flagged isDemo so Offers & Deals can mark it Demo
  • for a room created with Leave brand an unclaimed guest checked, every push and offer-minting effect was held rather than delivered, detected from the room's own participant state — nothing extra to pass in
  • every scripted line was consumed, so the run reached the end of the script
  • no participant's guidance appeared in another's memory slice, and the planner's private branch in nobody's
  • nothing was spent, and every model id still starts with mock:

The result renders as a pass/fail banner, the problems if any, the goal and offer comparison, and a collapsible transcript with each pushed message marked so you can see the cross-pane wakes land.

A real cost showing up here is worth reading carefully: if the offending run's model id still starts with mock:, that agent was routed correctly and simply ran past the end of its script, so the script needs another beat. If it does not, that agent was never routed through the mock at all — which is the bug the whole scripted-replay exercise exists to catch.

Driving the room afterward

The room the tab creates is left exactly where the script starts — nothing is sent automatically, so you drive it by hand in the Talent/Brand tabs.

A scripted agent ignores whatever you actually type and serves its next scripted line regardless, which is what makes the room usable for a demo as well as a test: you can type anything and the conversation still goes where the script says it goes.

If you keep going past the end of the script, the room does not error — it falls back to a real model for that one call and keeps the conversation running, logging a warning server-side. That is a deliberate difference from zreplay, whose headless runs assert that nothing costs anything; a fallback there is a signal the script needs another beat, not something to paper over. In the Playground, past the end of a script is simply past the end of a demo.

Where this fits

If you want to...Use
Draft or push a script from a terminal, in CI, or against a remote serverZauthor and Zpush
Run a scenario headless in CI, with a non-zero exit code on failureZreplay
Draft, upload, or push a script and click into the roomThis tab
Run a whole scenario and read its assertions without a terminalThis tab's Run full flow

The script format itself — panes, human blocks, beats, @offer — is the same everywhere and is documented once, on the Zauthor page.