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:
| Scene | Face | Stages | On stage |
|---|---|---|---|
sales-and-accounting | π€ | sales-and-accounting | Odoo, through odoo-accounting |
month-end-close | π | month-end-close | Odoo, through odoo-accounting |
crop-monitoring | π°οΈ | crop-monitoring | NASA Earthdata, through earthdata |
disaster-assessment | π¨ | disaster-assessment | NASA Earthdata, under each specialist |
coding-agent-behind-the-shield | π | its cast, written inline: code-explainer | One 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:
| Scene | Face | What 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β
| Part | What it says |
|---|---|
name, description, icon, emoji | Its 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 cast | The 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. |
setting | The 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. |
script | The 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. |
stage | Directions 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. |
audience | Who 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). |
rehearsal | The 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. |
deployment | Under 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:
| Field | What it says |
|---|---|
who | The member moving, by its id in the cast. |
asks | Whom: 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. |
over | a2a to a member, mcp to a system. |
what | What it asks for, or what it answers, in words. |
tool, does | Over 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. |
answers | What 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:
| Backdrop | What the stage looks like |
|---|---|
studio | Characters with speech balloons; each message flows along its line. Every scene that says no backdrop is drawn this way. |
hero | Round faces on a deep tint, thin lines, and a dot that flies with each message, out while asking and back while answering. |
plain | Boxes and arrows that do not move, the state written on each arrow: for a printout or a slide. |
space | Glowing 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. |
minimal | Glowing 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. |
orb | Each 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
mcpto one that is not a system of the scene; a move overa2ato 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
readwhen 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.