Skip to main content

Scenes

A scene stages a team. The team says who is on stage β€” its members, their roles, who asks whom over what; the scene says what happens there: the setting, the script, the stage directions, the audience, the rehearsal and where it plays. Its spec is the scene spec, schema: loop.scene/v1, one YAML per scene under agentspecs/scenes/. Nothing of membership is said twice: a scene names its team, or writes a cast that makes one.

Five scenes are the demo stages β€” the home page's four and a coding agent behind the Shield β€” each with its face, drawn before its name wherever scenes are listed, and each drawn on the hero backdrop:

SceneFaceStagesOn stage
sales-and-accounting🀝sales-and-accountingOdoo, through odoo-accounting
month-end-closeπŸ“’month-end-closeOdoo, through odoo-accounting
crop-monitoringπŸ›°οΈcrop-monitoringNASA Earthdata, through earthdata
disaster-assessment🚨disaster-assessmentNASA Earthdata, under each specialist
coding-agent-behind-the-shieldπŸ”’its cast, written inline: code-explainerOne repository, lent to read, behind the Shield

Six more stage the agent protocols β€” a person's own agent and a company, a business, a merchant β€” played as written, with nothing live behind them, on the studio backdrop:

SceneFaceWhat it shows
pact-a-personal-agent-at-a-business✈️Ada’s Travel Desk asks an airline about her flight, and she allows it to read her bookings, not to change them.
pap-a-person-and-a-companyπŸ§₯Ada’s agent asks a shop about her order, and she signs in at the shop itself.
pap-approve-onceπŸ”The shop proposes an exchange; Ada approves its exact terms, and it is done once.
pap-two-companies🏦An accounting firm pays a bill at Ada’s bank, and every payment is Ada’s approval.
pap-your-application-a-companyπŸͺAn application built in the Studio answers people’s own agents as a company does.
ucp-a-purchase-approvedπŸ›οΈAda’s Shopping Desk fills a basket at a test shop, and buys only once she approves the exact purchase.
# scenes/sales-and-accounting.yaml
schema: loop.scene/v1
id: sales-and-accounting
name: Sales & Accounting
description: A sales desk asks Accounting for the figures and hands them over.
icon: people
emoji: "🀝"

team: sales-and-accounting:0.0.2
cast:
- member: sales
persona: { name: Sales, line: I take your request and bring the figures back. }
brief: Ask Accounting for every figure; report what it answers.
- member: accounting
persona: { name: Accounting, line: I read the books and answer; I change nothing. }

setting:
systems:
- server: odoo-accounting:0.0.1
as: Odoo
holds: Datalayer's own books, read only.
assumes: Two agents over A2A, on Datalayer's own books in Odoo, read only.

script:
- id: open-invoices
cue: { say: Which customer invoices are still open, and how much is due in total? }
narration: Sales takes the request and asks Accounting, which reads the books.
moves:
- { who: sales, asks: accounting, over: a2a, what: the open invoices and the total due }
- { who: accounting, asks: odoo, over: mcp, tool: odoo_accounting_list_invoices, does: read }
- { who: accounting, answers: table, what: the open invoices by customer }
- { who: sales, answers: words, what: what Accounting answered }
expect: A table of the open invoices with one total that matches the books.
shows: [table]
branch:
- decision: the books hold no open invoice
expect: Sales says so in a sentence, and invents no figure.

stage:
backdrop: hero
positions: { sales: { x: 0.25, y: 0.5 }, accounting: { x: 0.75, y: 0.5 } }
opens_first: sales
transcript: { tools: true, withhold: [ids] }
inspectors: [agent, a2a, tools]
rests_after: 10m

audience: { who: visitors, ceiling_per_ask: 0.05, asks_a_day: 5 }

rehearsal:
beats:
- beat: open-invoices
lines:
- "You β†’ Sales"
- "Sales β†’ Accounting"
- "Accounting β†’ Odoo: odoo_accounting_list_invoices"
- "Accounting: a table"
must_say: [invoice]
must_not_say: [I cannot, error]
within: 120s
recording:
path: sales-and-accounting/recording.json
taken: "2026-10-29"
note: Rehearsed on Datalayer, under the demo account.

deployment:
account: demo
page: /
addresses: { accounting: DATALAYER_DEMO_TEAM_ACCOUNTING_A2A_URL }

What a scene spec holds​

PartWhat it says
name, description, icon, emojiIts face, exactly as an application has one: the tabs and the lists draw the emoji before the name. A scene's face is its own, never a member's.
team or castThe team it stages, or a cast written inline that makes one. On either, a cast member's persona on stage β€” the name the audience sees, its face, one line of who I am here β€” and its brief, laid over its application's instructions.
settingThe stage: the systems on it (the MCP servers the cast reaches, each with the name the audience reads, as, and what it holds), the shared frames, the contents in play, the period and the language, and assumes: what the audience is told before it starts β€” the line under the title.
scriptThe beats, in order. Each a cue (something the audience may say β€” the entry's suggestions on the page β€” a schedule or an event), its moves, expect in words, a narration line for the audience, what it shows (a table, a chart, a notebook β€” so the page can promise it), its pace, and the branch it takes on a decision.
stageDirections for the page: where each member stands (positions, fractions of the box), whose balloon opens_first, what the transcript shows (tool lines, narration) and withholds (credentials, ids), which inspectors are offered, how long the scene plays before it rests (rests_after), the pace of the beats that say none, and the backdrop the stage is drawn with wherever the scene plays: studio (characters with speech balloons, each message flowing along its line), hero (round faces on a deep tint, thin lines, a dot that flies with each message), plain (boxes and arrows that do not move, for a printout or a slide), space (glowing marks on a dotted, meshed ground, luminous lines and a light that flows with each message) minimal (glowing circles in each member's colour on a dark ground, nothing more) or orb (each member Datalayer's orb in its own colour); studio when unsaid.
audienceWho may watch and ask β€” visitors on the trial key, signed-in people, nobody (a rehearsal only) β€” and what a visitor's ask may cost (ceiling_per_ask, asks_a_day).
rehearsalThe scene's tests: for each beat, the shape the transcript must take (lines), the words that must_say and must_not_say, and the time it may take (within); a recording for when the scene cannot play live; what was verified, as an application's tests say it. A passing rehearsal is the gallery's Live.
deploymentUnder which account the scene plays, on which page, and for each member on a runtime the variable its address is read from at build (addresses).

A scripted scene​

A scene that says kind: scripted stages no team. It names its actors β€” a person, an application, a company, each an id, a name, a face and what it is β€” and writes its lines, played as written with nothing live behind them. live says, in a sentence, what of it is live on Datalayer today. The six protocol scenes above are written this way.

# scenes/pap-approve-once.yaml
schema: loop.scene/v1
id: pap-approve-once
kind: scripted
name: A Change, Approved Once
emoji: πŸ”

actors:
- { id: ada, name: Ada, face: πŸ§‘, is: the person }
- { id: agent, name: Her agent, face: πŸ€–, is: "an application on Datalayer, working for Ada" }
- { id: manzanita, name: Manzanita Outfitters, face: πŸ§₯, is: "a company, at manzanita.example" }

lines:
- from: ada
to: agent
says: "β€œIt is not warm enough: exchange it for the insulated one.”"
- from: agent
to: ada
says: "Its rule says Ask me first: it waits for Ada."
card:
kind: approval
title: Manzanita Outfitters asks you to confirm
rows: [[Order, ord_7Hk2], [Price difference, USD 70.00], [Version, "1"]]
how: The summary is the company’s own sentence, never the model’s.
turn:
"yes": Approve
"no": Decline
declined: "Ada declined: her agent tells Manzanita no, and nothing is exchanged."

live: >-
The approval card on Waiting for you is built in the Studio; a company’s
exchange approved through Datalayer waits for the services to be shipped.

Each line is from an actor, optionally to another, and says what they say or do; a card is what the audience reads (kind, title, rows, lines), how what happened underneath, and turn where the audience takes the person's part and decides.

A move​

A move is one member asking another over a protocol, or answering the audience:

FieldWhat it says
whoThe member moving, by its id in the cast.
asksWhom: a member (over a2a) or a system of the setting (over mcp), by its id or the name it is shown as. Nobody when the member answers the audience.
overa2a to a member, mcp to a system.
whatWhat it asks for, or what it answers, in words.
tool, doesOver mcp: the tool, by name or pattern (odoo_accounting_*), and what kind of tool it is (read, write, …), checked against what the server says of it.
answersWhat kind of answer comes back: words, table, chart, notebook, map, file, image, sources (cards that open), choice (buttons that answer the application), approval (a choice whose option does more than read: asked of a person, refused to a visitor).

The backdrop​

stage.backdrop says how the stage is drawn, here and wherever the scene plays β€” in the Studio, on a stage of its own, on the home page:

BackdropWhat the stage looks like
studioCharacters with speech balloons; each message flows along its line. Every scene that says no backdrop is drawn this way.
heroRound faces on a deep tint, thin lines, and a dot that flies with each message, out while asking and back while answering.
plainBoxes and arrows that do not move, the state written on each arrow: for a printout or a slide.
spaceGlowing round marks with a halo, the name beside each, on a ground of dots, grid, triangle mesh and rings, as the site's hero drawings; thin luminous lines, and a light that flows along the line with each message. In the page's light and dark colours.
minimalGlowing circles in each member's colour on a dark ground, in the light mode and the dark one alike β€” no name, no face, no words; thin lines, and a light that flows along the line with each message. A circle's details open in a card on hover, and stay open on a click.
orbEach member Datalayer's orb β€” a sphere whose colours swirl inside it, faster as it works β€” in its own colour (color on its agent, by palette name), its name and where it runs under it; luminous lines, and a light that flows along the line with each message. In the page's light and dark colours.
stage:
backdrop: hero
positions: { sales: { x: 0.25, y: 0.5 }, accounting: { x: 0.75, y: 0.5 } }

The transcript's shape​

A rehearsal says the shape a beat's transcript must take, line by line, in the words the transcript writes: You β†’ Sales (the audience asks), Sales β†’ Accounting (an ask over A2A), Accounting β†’ Odoo: odoo_accounting_* (a tool of a system, by name or pattern) and Accounting: a table (an answer, and what kind). Every name is one on stage; every tool one a connection offers.

A member whose agent runs a coding harness (OpenCode, Claude Code…) acts in its workspace, and each of its steps is a line: Code Explainer β†’ its workspace: Read README.md. Every step is decided by the Shield in front of the harness, by the application's Rules; a step it refuses is a line marked refused, and its drill-down on the stage shows the rule. Only a member that runs a harness has a workspace (harness_of).

The rehearsal that was played​

What the last rehearsal found is kept beside the specs, in the scene's own file <id>/rehearsal.json (played_path), written by loop scenes rehearse --cloud and never by hand: when it was played, where, whether every beat passed, the verdict in one sentence, each beat's verdict (passed, failed with what differed, not_run with why) and the agent-runtimes that played it. scene_played(id) reads it as a ScenePlayed, write_played keeps one, and a file that is not a rehearsal's result is refused in a sentence rather than read as a pass. A scene whose last rehearsal passed is Live β€” in loop scenes ls, in the catalogue agent-runtimes generates and on the home page; one that did not says so with the verdict's sentence. The hand-written verified sentences stay what a person says of the scene beside it.

The recording​

A scene that cannot play live β€” its runtime asleep, its system down β€” plays its recording instead: one transcript taken from a passing rehearsal, kept beside the specs in <id>/recording.json (recording_path), and named in the spec:

rehearsal:
recording:
path: sales-and-accounting/recording.json
taken: "2026-10-29"
note: Rehearsed on Datalayer, under the demo account.

The file is the transcript a stage exports with Export JSON β€” {version: 1, scene, lines}, each line who said or did what to whom and when β€” written by loop scenes record from a rehearsal that passed. A stage plays it at the pace it was recorded, under the label Recording, taken <date>, and a line of it opens in the drill-down with no span behind it. scene_recording(id) reads it, and refuses in a sentence a file that is not a transcript of version 1.

What is refused​

scene_problems says what stops a scene from being played, in sentences:

  • A cast member that is not a member of the team, or one that says what it is when the team already does.
  • A beat's mover not in the cast; a system that moves (it answers tool by tool and asks nobody).
  • A move over mcp to one that is not a system of the scene; a move over a2a to a system; a member asking one the team does not have it talk to; a system a member reaches through no connection.
  • A cue that nobody answers: a beat with no move of the entry's.
  • A tool no connection offers, in a move or in a rehearsal line; a tool asked to read when the server says it writes.
  • A system on stage that no member of the cast reaches; a Frame or a server the catalogue does not have.
  • A visitor audience on a scene whose member on a runtime has no address in deployment.addresses; an address for a member in the browser.
  • A rehearsal naming a beat that is not in the script, or a name that is not on stage; a step in the workspace of a member that runs no harness; a recording that is not beside the scenes.
  • A scene wearing a member's face.

What a scene needs that is not offered today is setup, not a mistake (scene_setup): its members' applications' own.

from agentspecs.scenes import get_scene, scene_problems, scene_setup

scene = get_scene("sales-and-accounting")
scene.team_of().links() # [('sales', 'accounting', a2a)]
[m.persona.name for m in scene.cast_of()] # ['Sales', 'Accounting']
scene.cues() # the three things the audience may say
scene.script[0].shown # [AnswerKind.TABLE]
scene_problems(scene) # []
scene_setup(scene) # what is not enabled yet, in sentences

The JSON Schema of the spec is written beside the scenes (agentspecs/scenes/loop.scene.schema.json) by python -m agentspecs.scenes, with the reference of every field.