$ cat workspace-template.yaml

L

Libreria Layout del Brand

// Crea e gestisce la libreria di layout PowerPoint di un brand, anche partendo da zero. Senza un master: l'agente progetta i layout come slide (copertina, agenda, sezione, testo e immagine, elenco, tabella, numeri chiave, chiusura e altri) con i colori, i caratteri e il logo del brand, li trasforma in un master PowerPoint, lo salva nella cartella Drive scelta e lo pubblica come libreria con il nodo Brand Master. Con un master già pronto (.pptx o .potx in Drive) lo pubblica direttamente. Poi si curano i layout (nomi, descrizioni, attivi o no), se ne aggiungono o se ne cambiano i colori; le presentazioni si fanno in altri workspace con il template "Presentazione PPTX dalla Libreria Layout". Scrive solo il file del master nella cartella Drive scelta. Il controllo visivo dei layout richiede un modello con visione potente: funziona con Claude Opus 5.5, mentre Qwen 3.6 può dare per buoni layout illeggibili. Creates and manages a brand's PowerPoint layout library, from scratch if needed. Without a master, the agent designs the layouts as slides (cover, agenda, section, text and picture, bullets, table, key numbers, closing and more) in the brand's colours, fonts and logo, turns them into a PowerPoint master, saves it to the Drive folder you choose and publishes it as a library with the Brand Master node. With an existing master (a .pptx or .potx in Drive) it publishes that one. Then you curate the layouts (names, descriptions, on or off), add layouts or change the colours; decks are made in other workspaces with the "Presentazione PPTX dalla Libreria Layout" template. It writes only the master file, into the Drive folder you choose. The visual check of the layouts needs a strong vision model: it works on Claude Opus 5.5, while Qwen 3.6 can report unreadable layouts as fine.

Document Generation
#pptx#powerpoint#master#template#brand#layout#libreria#library#presentazione#presentation#slides#brand kit

// Canvas Preview

canvas.flow

// Instruction

instruction.md

Libreria Layout del Brand

Template ID: assigned by each marketplace when the template is published (source: fixture apps/marketplace/fixtures/workspace-templates/brand-layout-library.workspace.json, built by scripts/brand-layout-library/build_template.py).

This workspace IS a brand's layout library: its ONE "Brand Master" publishes the PowerPoint master's layouts, and decks made in OTHER workspaces (template "Presentazione PPTX dalla Libreria Layout") read them through a Layout Library node. Two ways to get the master: create — the brand has no master: twelve Slide Generators ("Layout: …") design the layouts as slides in layout design mode, in the style of "Design del Brand" (the brand's design.md), "Componi i Layout" (Presentation Composer) dresses them in the brand kit (colours, fonts, logo), "Crea il Master" turns every slide into a layout of a PowerPoint master, "Salva il Master" saves it into the Drive folder the user chose, and "Brand Master" publishes it; upload — the brand has a master (.pptx/.potx in Drive): "Brand Master" publishes that file. Then you curate the layouts (names and descriptions), and on later turns change the brand, add, redesign or remove layouts.

create: "Design del Brand" ─design─→ every "Layout: …"         "Logo del Brand" ─logo─┐        "Layout: Copertina" … "Layout: Chiusura" → "Raccogli i Layout" → "Componi i Layout" (brand kit)          → "Crea il Master" → "Salva il Master" (Drive folder) → "Brand Master" → library        "Componi i Layout" → "Anteprima dei Layout" (one image per layout: the visual check)        "Crea il Master" → "Anteprima del Master" (the master as PowerPoint draws it: the master check)upload: Drive .pptx/.potx → "Brand Master".driveItemId → library

You MUST complete all 4 phases in order: Phase 1 → Phase 2 → Phase 3 → Phase 4. Do NOT skip any phase. (Upload skips the design steps 6–8 inside Phase 2, nothing else.) When this instruction reaches you as a section index, load each phase's section before entering it, starting with loadInstructionSection({ sectionId: "phase-1-setup" }). NEVER set llmModelId on any node: leave it empty. NEVER change a layout's layoutName once the master is published: it is the layout's id in the library.

Overview

A brand manager or curator asks for "il nostro template PowerPoint", "una libreria di layout per il brand X", or to change one ("cambia il colore", "aggiungi un layout con tre colonne"). The library is the "Brand Master" node's latest completed run; it holds the master file, one background and thumbnail per layout, and the catalog (each layout's slots with their capacities, plus the curation: label, description, on/off). In create mode the layouts are designed, not drawn: each "Layout: …" node is a Slide Generator whose layoutName makes it write a reusable layout (placeholders marked, short guidance as sample text) on one Emblema layout (template_name), in the brand's style from "Design del Brand" (corners, borders, shadows, type: brand-design); the brand kit on "Componi i Layout" re-colours and re-fonts them; "Crea il Master" lays the deck out in a browser and writes one PowerPoint layout per slide (the slide's look as background, its title, text, lists, picture, table and slide number as placeholders). Writing outside the workspace happens only in "Salva il Master" (the master file, into the folder the user named at step 4).

Workflow Chain

[create]"Logo del Brand" (Drive Image Reader, optional) .image → "Componi i Layout".logo"Design del Brand" (Text, the brand's design.md) .value → every "Layout: <Name>".design"Layout: <Name>" ×12 (Slide Generator, layoutName = <Name>) .slide_html → "Raccogli i Layout".item_<n>"Raccogli i Layout" (Make Array) .items → "Componi i Layout" (Presentation Composer, theme emblema, brandKit) .slides"Componi i Layout".presentation → "Crea il Master" (Master from Slides) .presentation"Componi i Layout".presentation → "Anteprima dei Layout" (Snapshot) .html → images (step 7a)"Crea il Master".master → "Salva il Master" (Save File, destinationFolder) .file"Crea il Master".preview → "Anteprima del Master" (Snapshot) .file → images (step 9a)"Salva il Master".driveItemId → "Brand Master".driveItemId → library (catalog, master, backgrounds, thumbnails)
[upload]"Brand Master".driveItemId = the brand's .pptx/.potx (edge "Salva il Master" → "Brand Master" deleted at step 5)
[add a layout] "Layout #x" (prototype) → expandPrototype (feed: the design) → "Layout: <Name>" → "Raccogli i Layout".item_<next>

Node Reference

Canvas labels are Italian; match them exactly with nodeFinder. After applyCanvasData the nodesPreview ids are dead: re-resolve every label.

  • "Logo del Brand" (Drive Image Reader) — driveItemId (a PNG, JPEG or WebP in Drive, at most 2 MB) → image, wired to "Componi i Layout".logo. The composer silently refuses anything else, an SVG included, and the deck keeps no logo with no error: never offer or use an .svg as the logo. When the user names one, say it is not accepted and ask for a PNG. No logo → its edge is deleted at step 5 (the node stays, unwired and unset).
  • "Design del Brand" (Text) — value = the brand's design.md (brand-design), wired to the design input of every "Layout: …" node, where it ranks above the instruction. It ships with only a comment (<!-- … -->), which the layouts read as no design: the Emblema look. Never empty it (a Text node needs a value): to drop the style, write a comment back.
  • The twelve layouts (Slide Generator, layout design mode), in "Raccogli i Layout" pin order: "Layout: Copertina" (emblema-cover), "Layout: Agenda" (emblema-agenda), "Layout: Sezione" (emblema-section), "Layout: Testo e immagine" (emblema-two-col), "Layout: Elenco puntato" (emblema-bullets), "Layout: Racconto con foto" (emblema-magazine), "Layout: Citazione" (emblema-statement), "Layout: Numeri chiave" (emblema-kpis), "Layout: Tabella" (emblema-table), "Layout: Confronto" (emblema-compare), "Layout: Processo" (emblema-process), "Layout: Chiusura" (emblema-closing). Inputs: layoutName (the layout's id in the library — the part after "Layout: "), template_name (the Emblema layout it is designed on, or auto for a free design in the brand's theme), instruction (what the layout holds), content (required; only hints the topic), language, design (← "Design del Brand"; never typed on a layout), fixedLayout. Output slide_html. The twelve ship with fixedLayout: true: the node draws the layout's fixed structure and sample text with no model, the same every time, so instruction is ignored and only the design's ```css block applies. Sample text exists in Italian and English; with another language (step 5) the node asks the model. A layout you add has no fixedLayout, and the model draws it from its instruction.
  • "Layout #x" (Slide Generator, prototype) — standalone, not wired. NEVER execute or delete it; it exists only for expandPrototype (a new layout).
  • "Raccogli i Layout" (Make Array) — pin order = layout order in the master; item_0 … item_11 are the starter set.
  • "Componi i Layout" (Presentation Composer) — theme MUST stay emblema (the brand kit applies only to it); canvas MUST stay 1280x720 (it sets how large the text comes out on the slide); brandKit = { "name": "<brand>", "colors": { "primary": "#RRGGBB", "text": "#RRGGBB", "background": "#RRGGBB" }, "fonts": { "heading": "<font>", "body": "<font>" } } (every key optional, and set a colour only if the user named it; text is the colour of all the text on the slides, so white there makes every title invisible on the white backgrounds; background replaces the white slide backgrounds — a dark one makes the text white unless text is set); logo ← "Logo del Brand"; title = the brand name. Fonts must come from this list, else they are ignored: IBM Plex Sans, IBM Plex Mono, Source Sans Pro, Montserrat, Arial, Helvetica, Georgia, Times New Roman, Verdana, Trebuchet MS, Calibri, Cambria, Segoe UI (the first four are web fonts: PowerPoint shows them only where they are installed). Its node preview shows the designed layouts.
  • "Anteprima dei Layout" (Snapshot) — html ← "Componi i Layout".presentation. Outputs images (Image[], one PNG per layout in "Raccogli i Layout" pin order: image n is the n-th layout) and pages. Nothing reads it, so running "Brand Master" never runs it: only step 7a does. Writes nothing outside the workspace.
  • "Crea il Master" (Master from Slides) — presentation ← "Componi i Layout"; name = the brand name (the file and theme name). Outputs master (File), layouts (Number) and preview (File: one slide per layout with its sample text, to look at, never to save as the master). Writes nothing outside the workspace.
  • "Anteprima del Master" (Snapshot) — file ← "Crea il Master".preview. Outputs images (Image[], the master as PowerPoint draws it, one PNG per layout in the same order as "Anteprima dei Layout") and pages. Nothing reads it, so running "Brand Master" never runs it; only step 9a does.
  • "Salva il Master" (Save File) — file ← "Crea il Master".master; destinationFolder = the Drive folder from step 4 (required). Output driveItemId. Writes the master into Drive; running it again overwrites the same file.
  • "Brand Master" — driveItemId (create: ← "Salva il Master"; upload: the brand's file) and curation (labels, descriptions, on/off per layoutId). Running it publishes the library (a cache hit when nothing changed). Only ONE Brand Master may exist in this workspace. Outputs library, catalog, master, backgrounds, thumbnails; never read library or catalog with getNodeOutput (they are large): read its layouts output instead (step 10), one line per enabled layout.

Brand Design

"Design del Brand" holds the brand's design.md: the STYLE the brand kit cannot carry. The brand kit owns the colours and the fonts; the design says how the surfaces look: corners, borders, shadows, fills, the weight and case of the type, labels, markers. Every "Layout: …" node reads it and keeps its Emblema layout's structure: the twelve fixed layouts apply only its ```css block, so a style that is not in that block does not appear on them; a layout you added also reads the words and ranks them above its instruction. A style is ALWAYS the design, never words in the layouts' instructions (there it only reaches the speaker notes).

Write it in the user's language with concrete values, not adjectives ("bordo 4px", "ombra 10px 10px 0", "peso 800, maiuscolo", never just "deciso"): a title line, then short lists for the principles, the shapes (corners, borders, shadows, fills, dividers), the type (titles, labels, body, big numbers) and the details (markers, icons, page number), then ONE ```css block of base rules, which every layout applies (cleaned by the same rules as the layout's own CSS): put there what must be identical on every layout.

Rules for the whole design, its CSS included (the layouts remove what breaks them):

  • Colours only as the theme's variables, which carry the brand kit: var(--et-500) (the primary), var(--et-600) (darker), var(--et-300), var(--et-100), var(--et-50) (lighter tints), var(--text-primary), var(--text-secondary), var(--text-tertiary) (muted), var(--bg), var(--bg-card), var(--border-strong), var(--border-subtle) (hairlines), transparent. Never a hex value, a colour name or rgba(): the whole declaration is removed. A soft shadow takes a hairline: box-shadow: 0 8px 24px var(--border-subtle). A colour the brand lacks belongs in the brand kit.
  • No font family (font, font-family): the brand kit's. Weight, case, letter-spacing and line-height are the design's.
  • Sizes are on a 1280x720 canvas, where 1px is 0.75pt. Never set body text under 18px or any text under 13px: it is too small to read in a room. No font size on .eyebrow: above the theme's 13px, the master no longer keeps a long label on one line.
  • No text colour or font size on h1, h2, p, li, section * or any rule that reaches every layout. The theme already writes white on its dark slides (Sezione, Chiusura, the cover's panel), and a colour there makes them unreadable; a size on p also shrinks the quote of Citazione. Colour one element only (.eyebrow, .kpi .num).
  • What the theme draws until the CSS overrides it, so settle each one against the style: titles in capitals (text-transform) and light (font-weight: 300 on h1, h2); corners of 4px on .visual, .kpi, .col, .step; no shadows; a soft glow on .slide-cover .right::after and .slide-section::before; a gradient and dots on .photo and .slide-closing .right; a 3px bar on .divider, .kpi (top) and .step (left).
  • No geometry: the layouts keep their positions and sizes (display, position, width, height, flex, grid, gap, transform are removed on their elements). A divider's thickness is a border-top, not a height.
  • Plain CSS: selectors joined by a space or > (never +, ~, :is() or :has()), values of numbers, keywords, the colour variables and gradients. @-rules, url(), !important, custom properties (--x) and comments are removed.
  • Selectors on the Emblema classes: h1, h2, h3, h4; .eyebrow (labels); .divider; .marker, .icon; .num (big numbers); .photo, .visual (photo boxes); .kpi, .step, .col, .card, .phase (cards); table (never its corners: a PowerPoint table has square ones); and section *, section *::before, section *::after for a rule on everything (e.g. border-radius: 0).

Example, "stile neobrutalista":

Design del brand: neobrutalismo
Principi- Blocchi piatti e netti: niente sfumature, bagliori od ombre morbide. Angoli vivi.Forme- Card, riquadri foto e tabelle: bordo 4px e ombra dura 10px 10px 0, in var(--text-primary).- Riempimenti pieni: var(--et-500) o var(--bg-card); mai gradienti.Tipografia- Titoli: peso 800, maiuscolo. Etichette: piene in var(--text-primary), testo var(--bg). Numeri grandi: peso 900.CSS di base (applicato a ogni layout)```csssection *, section *::before, section *::after { border-radius: 0; }h1, h2, h3, h4 { font-weight: 800; text-transform: uppercase; line-height: 1.05; }.eyebrow { background: var(--text-primary); color: var(--bg); font-weight: 700; padding: 6px 12px; }.photo, .visual, .kpi, .step, .col, .card, .phase, table { box-sizing: border-box; border: 4px solid var(--text-primary); box-shadow: 10px 10px 0 var(--text-primary); }.divider { border: 0; border-top: 6px solid var(--text-primary); background: none; }.marker, .icon { background: var(--text-primary); color: var(--bg); }.kpi .num, .step .num { font-weight: 900; color: var(--text-primary); }.photo, .slide-closing .right { background: var(--et-500); }.photo::after, .slide-cover .right::after, .slide-closing .right::after, .slide-section::before { background: none; }```

Execution Strategy

You MUST complete all 4 phases in order: Phase 1 → Phase 2 → Phase 3 → Phase 4. Do NOT skip any phase.

Phase 1 = steps 1–5 · Phase 2 = 6–8 (with 7a) · Phase 3 = 9–12 (with 9a) · Phase 4 = 13–15. Numbering is continuous.

Gates: Phase 1 ends with ONE requestUserDecision (only for what the message left open; the Drive folder answer is the user's consent to "Salva il Master" writing there); Phases 2–4 run without pauses.

Global rules:

  • After nodeExecutor the system notifies on completion — do NOT poll getNodeOutput in a loop.
  • On a tool error retry up to 3 times with corrected parameters; then ask the user. Never skip a step.
  • applyCanvasData is used once, at step 1. Later changes use expandPrototype or atomic tools.
  • followUp is called only at step 15.

Phase 1: Setup

Gate keys: source, brandName, primary, font, folder (create) — source, masterFile (upload). All must be resolved by the end of step 5.

  1. applyCanvasData → IMMEDIATELY commit the template, before any other tool call. (A canvas that already has "Brand Master" and the "Layout: …" nodes from an earlier turn is an EDIT: go to incremental-edits-to-an-existing-library instead.)
  2. Extract what the ORIGINAL message already says (no tool calls): known.source = upload when it attaches or names a PowerPoint master/template (.pptx/.potx) or says the brand already has one, create when it asks to create/design one; known.brandName (a quoted or obvious brand name); known.primary (a hex colour, or a named colour you convert to hex); known.background (only when the message asks for a slide background: "fondo nero", "tema scuro", a hex); known.font (a font from the list in node-reference); known.style (a style the message names: "neobrutalista", "minimal", "editoriale", "anni '80"); known.logo (an attached or @mentioned image); known.folder (an attached/@mentioned Drive folder, or a folder name); known.masterFile (an attached/@mentioned .pptx/.potx). Print one line naming what you extracted and what you will still ask.
  3. Resolve Drive names to ids: a name, not a chip → searchDriveItems({ query: "<name>" }) (folders for folder, images for logo, .pptx/.potx for masterFile). Exactly one match → its id. 0 results → one shorter query; still nothing → leave it null (it is asked at step 4). Never retry the same query.
  4. Phase 1 gate — ask ONLY what is still null, in ONE call. Never call requestUserDecision more than once in Phase 1; if nothing is missing, do not call it. Skip the create-only questions when known.source = upload, and masterFile when it is create:
requestUserDecision({  questions: [    { key: "source", question: "Il brand ha già un master PowerPoint, o lo creiamo da zero?", header: "Master",      options: [ { id: "create", label: "Crealo da zero", description: "Progetto i layout con i colori e i caratteri del brand", recommended: true },                 { id: "upload", label: "Ho già un master", description: "Un file .pptx o .potx in Drive" } ] },    { key: "brandName", question: "Come si chiama il brand?", header: "Brand", options: [] },    { key: "primary", question: "Qual è il colore principale del brand?", header: "Colore",      context: "Scrivi un codice esadecimale (es. #1E6F7F) o scegline uno.",      options: [ { id: "#1F4E79", label: "Blu" }, { id: "#1E6F7F", label: "Verde acqua" }, { id: "#B71C1C", label: "Rosso" }, { id: "#4A148C", label: "Viola" } ] },    { key: "font", question: "Quale carattere usiamo?", header: "Carattere",      options: [ { id: "IBM Plex Sans", label: "IBM Plex Sans", recommended: true }, { id: "Arial", label: "Arial" }, { id: "Georgia", label: "Georgia" }, { id: "Calibri", label: "Calibri" } ] },    { key: "folder", question: "In quale cartella Drive salvo il master?", header: "Cartella",      context: "Il master viene rigenerato a ogni modifica fatta qui: le modifiche fatte al file in PowerPoint vengono sovrascritte.", options: [] },    { key: "masterFile", question: "Quale file è il master del brand?", header: "File", options: [] }  ]})

Write the questions in the user's language. Merge: source ← known / answer [create]. primary ← a selected id or otherText that is a hex colour (# + 6 hex digits; a named colour → its hex). font ← a selected id or an otherText in the font list, else IBM Plex Sans. brandName, folder, masterFile ← otherText; resolve folder/masterFile names as in step 3. Cancelled, or folder (create) / masterFile (upload) unresolved → STOP: say what is missing and ask for it. Never write into a folder the user did not name. 5. Write the setup. Resolve ids with ONE nodeFinder call (queries: "Componi i Layout", "Crea il Master", "Salva il Master", "Logo del Brand", "Design del Brand", "Brand Master", "Layout:", "Layout #x"). - create → ONE batchUpsertNodes: "Componi i Layout" { brandKit: { name: <brandName>, colors: { primary: <primary>, text: <"#161616", or "#FFFFFF" when the background is dark>, background: <background, only when known> }, fonts: { heading: <font>, body: <font> } }, title: <brandName> }; "Crea il Master" { name: <brandName> }; "Salva il Master" { destinationFolder: <folder id> }; "Logo del Brand" { driveItemId: <logo id> } only when known.logo is set; "Design del Brand" { value: <the design.md for known.style, written as in brand-design> } only when known.style is set; and, when the user's language is not Italian, { language: "<code>" } on every "Layout: …" node and "Layout #x" (codes: it, en, zh, de, es, fr, ja, ko, nl, pt, ru). No logo → deleteEdge "Logo del Brand".image → "Componi i Layout".logo (an unset image reader would fail the run). - upload → deleteEdge "Salva il Master".driveItemId → "Brand Master".driveItemId (otherwise running the Brand Master would also design and save a master), then upsertNode "Brand Master" { driveItemId: <masterFile id> }.

Phase 1 complete. Now proceed to Phase 2. Do NOT skip to Phase 4.

Phase 2: Layout Design

upload: skip steps 6–8 and go to Phase 3.

  1. Layout requests in the message (none → go to step 7). The user named layouts to drop ("niente agenda") → deleteNode those "Layout: …" nodes (Make Array skips the empty pins). The user asked for a layout the starter set lacks ("una slide con tre colonne", "una per il team") → add it with ONE expandPrototype call, one item per new layout, each on a FREE pin of "Raccogli i Layout" (a pin with no incoming edge; with the starter set wired, 12 and up):
    expandPrototype({  prototype: { nodeIds: ["<Layout #x id>"] },  items: [ { label: "Layout: <Name>", pin: 12, config: { "<Layout #x id>": { layoutName: "<Name>", template_name: "<an Emblema layout id, or auto>", instruction: "Progetta <what the layout holds, with counts>." } } } ],  collector: { nodeId: "<Raccogli i Layout id>", fromPrototypeNodeId: "<Layout #x id>", fromHandle: "slide_html" },  feed: { fromNodeId: "<Design del Brand id>", fromHandle: "value", toPrototypeNodeId: "<Layout #x id>", toHandle: "design" },  layout: { groupLabel: "Layout del Brand" }})
    <Name> is short, unique among the layouts, in the user's language, and never "x". A layout holds AT MOST ONE photo: never design one with two or more.
  2. nodeExecutor "Componi i Layout" — it runs the logo reader, every "Layout: …" node and "Raccogli i Layout". Wait. Then read what the design lost, since each layout loses its own: one getNodeOutput({ nodeId: "<Layout: … id>", keys: "designDropped" }) per completed "Layout: …" node, in one response if you can, and read every one before you move on. A layout you could not read: say so at step 14. A declaration listed there was removed from that layout, so it did not apply: rewrite it with the allowed values and run this step once more, or say at step 14 that it did not apply. Never report it as applied. A geometry declaration (width, display…) stays removed on purpose. If it fails: find the failed nodes (nodeFinder({ filter: "failed" })) and read each errorMessage (getNodeOutput({ nodeId, keys: "slide_html" })). A failed "Layout: …" → run it once more and read its designDropped; still failing → deleteNode it and say that layout is left out. "Logo del Brand" failed → the file is not a readable image: deleteEdge its edge, run step 7 once more, and say the master has no logo. 7a. Look at the layouts — follow the skill Revisione Visiva (listed under <workspace_skills>: load it first, loadInstructionSection({ skill }) with its pin), with: images node "Anteprima dei Layout" (one image per layout, from the deck of step 7); record "Revisione dei Layout"; image n is layout n, counting only the layouts left after step 7, and its row's shows is the layout's name; all nine checks; the sample text ("Titolo, 3-6 parole") is expected. The skill is not available (the list says so) → skip to step 8 and add that the layouts are drawn on "Anteprima dei Layout" for the user to check.
    • The fixes allowed. Checks 1-4 are fixed where one of the two fixes below can solve them, checks 5-8 only when a rule in the design solves them, check 9 is reported unless the design was not applied. A problem of style (colour, contrast, shadow, corners, borders, type), on one layout or on many, or of margin, padding or text size → change "Design del Brand" (brand-design) with a rule inside its ```css block, the only part a fixed layout reads, that says where it applies (.kpi .num { color: var(--et-600); }), keeping the rest of its value; a problem of content or fit of a layout you added → upsertNode its instruction with the concrete fix ("titolo su massimo due righe", "al massimo 4 punti", "ogni punto su una o due righe"), NEVER a style there; on a layout with fixedLayout: true it is reported, since its structure does not change. These are the only two fixes: never change a layout's template_name or layout, and never re-run layouts one by one to refresh them. Neither fix can move a built-in layout's own blocks (its grid, its columns, where they sit on the slide): a problem only that would solve is reported. After a fix, step 7 again, then the skill's review again: a change to "Design del Brand" redraws EVERY layout, a change to one layout's instruction that layout alone. That run failed → keep the record and report its open problems at step 14.
    • What the skill leaves open is reported at step 14.
  3. Print the designed layouts (their names, in pin order) with the result of step 7a, and tell the user the preview is on "Componi i Layout".

Phase 2 complete. Now proceed to Phase 3. Do NOT skip to Phase 4.

Phase 3: Master and Library

  1. nodeExecutor "Brand Master" — create: it runs "Crea il Master", "Salva il Master" (the master goes into the folder from step 4) and the Brand Master; upload: the Brand Master alone. Wait. If it fails: read the failed node's errorMessage (nodeFinder({ filter: "failed" }), then getNodeOutput({ nodeId, keys: "master" }); library errors carry [LIBRARY] {"code":…}), apply ## Error Handling, tell the user, and STOP. 9a. Look at the master — create only. Follow the skill Revisione Visiva again, with: images node "Anteprima del Master" (the master drawn the way PowerPoint does, from the preview deck of "Crea il Master": one slide per layout, with its sample text); record "Revisione del Master"; image n is layout n, as at step 7a; checks 1-4 only, noting only what step 7a did not show: text that no longer fits its box or wraps where the layout did not; columns, cards or items merged into one block of text; a word's own colour, size or case lost (a placeholder has ONE style); a slot missing or moved; another typeface (on every layout it is a font the renderer lacks: say it once). Photo and table areas are empty in the preview: expected. No fixes: these come from the conversion, not the design, so do NOT change the layouts or "Design del Brand" for them; report each at step 14 with the layout's name.
  2. Read the library from the Brand Master's execution result: getNodeOutput({ nodeId: "<Brand Master id>", keys: "layouts" }). Its layouts output lists every enabled layout, one line each: layoutId "<id>" — label — description — slots — picture. Store it as layouts. No layouts in the result (the run did not complete, or the Brand Master is an older version without that output) → STOP and tell the user the layouts could not be read and that the Brand Master must be updated. Never guess a layoutId.
  3. Curate — write the labels and descriptions the deck agents choose by. nodeFinder({ queries: ["Brand Master"], includeConfig: true }) → read its current curation (an object keyed by layoutId; keep every entry already there, and in an entry you complete keep its fixedCount). For EACH layout in layouts (step 10) without a curated description, add { "<layoutId>": { "label": "<a short name in the user's language>", "description": "<one sentence: when to use it, and what it holds with counts, e.g. 'Apre una sezione: numero, titolo e una riga di introduzione.'>" } }. Copy each layoutId EXACTLY. Never set enabled: false unless the user asked to turn a layout off. Then ONE upsertNode({ nodeId: "<Brand Master id>", input: { curation: <the merged object> } }).
  4. nodeExecutor "Brand Master" — it publishes the curated library (only the Brand Master re-runs). Wait; on failure apply ## Error Handling.

Phase 3 complete. Now proceed to Phase 4.

Phase 4: Verification and Handoff

  1. Audit. nodeFinder({ queries: ["Brand Master", "Componi i Layout", "Salva il Master"], includeConfig: true }): exactly ONE "Brand Master"; create → its driveItemId is wired from "Salva il Master", "Componi i Layout" has brandKit and theme: emblema, "Salva il Master" has destinationFolder, on a first build the Brand Master's curation still has fixedCount: true on Agenda, Elenco puntato, Numeri chiave and Processo; upload → its driveItemId is set and nothing is wired into it. Fix a failure once (upsertNode / upsertEdge / deleteEdge), then re-run step 12 once.
  2. verification — one item per check of step 13, one for the library ("Libreria pubblicata: layout attivi"), one per layout left out or failed, one for each design rule that did not apply (step 7), one for the visual check of step 7a ("Controllo visivo: layout ok", each problem still open, or "non eseguito: "), one for the master check of step 9a ("Controllo del master: layout come nell'anteprima", each difference, or "non eseguito: "). Summary in the user's language: the brand, the master file name and Drive folder (create), the layouts. Create: say that every change made here rewrites that Drive file, so changes made to it in PowerPoint are lost: change the layouts in this workspace.
  3. followUp — say how decks use the library: in another workspace, the template "Presentazione PPTX dalla Libreria Layout", with this workspace chosen in its "Libreria Layout" node; share this workspace with the people who make decks. Suggest 2–3 next steps: refine names and descriptions in the Brand Master's "Cura layout" and press "Pubblica"; add a layout; give the layouts a style (e.g. "neobrutalista", "minimal"); change the colours, the font or the logo.

Incremental Edits to an Existing Library

Detection: "Brand Master" and the "Layout: …" nodes existed BEFORE this turn → this is an EDIT. Do not call applyCanvasData, do not ask the Phase-1 questions. A message that asks to build AND tweak is a build: run all phases, then apply the tweak before step 13. After a change to the style, the colours, the font or a layout's design, first run steps 7 and 7a (look at the layouts again). After any change below, nodeExecutor "Brand Master" (it re-runs only what changed, re-saves the master over the same Drive file and publishes), step 9a when the master was rebuilt, then steps 13–15.

  • Colours, font or brand name: read "Componi i Layout"'s brandKit (nodeFinder with includeConfig), change only what was asked, upsertNode the merged brandKit (and title / "Crea il Master" name for a new brand name).
  • Style ("stile neobrutalista", "più minimal", "angoli arrotondati", "titoli in maiuscolo"): read "Design del Brand"'s value (nodeFinder with includeConfig). A new style → write a new design.md (brand-design); a tweak → change only what was asked and keep the rest. upsertNode "Design del Brand" { value }. NEVER write a style into the layouts' instructions. Back to the Emblema look → { value: "<!-- Nessuno stile: il look Emblema. -->" }. Every layout designs again on the next run.
  • Logo: resolve the image (step 3; PNG, JPEG or WebP only, never an .svg), upsertNode "Logo del Brand" { driveItemId }, and upsertEdge "Logo del Brand".image → "Componi i Layout".logo if it is not wired. Remove the logo → deleteEdge that edge.
  • Add a layout: step 6's expandPrototype (with its feed: the new layout takes the design) with ONE item at the FIRST free pin of "Raccogli i Layout" — read its incoming edges (nodeFinder with includeConfig) and take the lowest item_N with none, never "count + 1" — WITHOUT layout (the section exists): leave the new node next to the section, organizeNodes + autoLayout. NEVER call sectionManager(group) on nodes already in a section, and never retry it after "already in a section". Then step 11 for the new layout.
  • A variant of a layout ("come Testo e immagine ma con la foto a sinistra", "una variante della copertina"): read the base "Layout: " node's template_name and instruction (nodeFinder with includeConfig), then Add a layout with template_name = the BASE's (NEVER another Emblema layout: another one designs a different slide, not a variant of this one), instruction = the base's instruction + " Variante: <the change, concretely>." and layoutName = " – <the change in 2-4 words>". The base stays as it is. A change the base's structure cannot hold (a second photo, a table in a quote, a different number of columns: the Emblema layout fixes its grid, "Elenco puntato" is always two columns) is not a variant: say so and offer a new layout instead.
  • Redesign a layout: upsertNode its instruction (and/or template_name) with fixedLayout: false, so the model draws it from them; NEVER its layoutName.
  • Rename, describe, turn on or off a layout: only the Brand Master's curation (label, description, enabled), merged as in step 11 — never layoutName.
  • Remove a layout: deleteNode its "Layout: …" node and remove its key from curation. NEVER wire a "Layout: …" node that already feeds a pin of "Raccogli i Layout" into a second pin: the layout would be in the master twice. Decks that used it show "layout not in the library" until they pick another.
  • The uploaded master changed in Drive: nothing to configure.
  • Switch between create and upload: the layoutIds change, so the curation no longer matches and decks lose their layouts. Ask ONE requestUserDecision to confirm first; then rewire as in step 5 and redo step 11.

Configuration Tips

User saysConfigure
"crea il template PowerPoint del brand Acme, blu, con il nostro logo"create; brandName Acme, primary a blue hex, logo from the attachment; ask only the folder
"ecco il nostro master" + a .pptxupload; masterFile = the attachment
"colore #7A1F5C" / "verde bosco"brandKit.colors.primary (named colours → hex)
"testo grigio scuro"brandKit.colors.text
"fondo nero" / "tema scuro" / "sfondo #111111"brandKit.colors.background (black → #000000) and text #FFFFFF
"carattere Georgia per i titoli"brandKit.fonts.heading (list in node-reference; others are ignored: say so)
"stile neobrutalista" / "più minimal" / "angoli arrotondati"Style: write or update "Design del Brand" (brand-design); never the layouts' instructions
"titoli più pesanti" / "tutto in maiuscolo"Style: the design's type rules (the font itself is the brand kit's)
"togli lo stile" / "torna al look normale"Style: "Design del Brand" back to a comment
"aggiungi un layout con tre colonne"Add a layout: template_name auto, instruction "tre colonne, ciascuna con titolo e testo breve"
"come Testo e immagine ma con la foto a sinistra"A variant of a layout: base "Layout: Testo e immagine" (emblema-two-col), same template_name, its instruction + " Variante: la foto a sinistra, titolo e testo a destra.", layoutName "Testo e immagine – foto a sinistra"
"voglio un layout con due foto"not supported: a layout holds one photo; offer one photo, or two text columns
"togli l'agenda"Remove a layout (or enabled: false in curation to keep it for later)
"chiama la copertina 'Apertura'"curation label — never layoutName
"il master non mi piace, rifallo"redesign the layouts named, or change the brand kit; never recreate the Brand Master
"come lo uso per una presentazione?"step 15's answer: the "Presentazione PPTX dalla Libreria Layout" template, this workspace in "Libreria Layout"

Error Handling

Library and render errors arrive in errorMessage as [LIBRARY] {"code":"…","params":{…}}, possibly after other text.

Error code / symptomCauseFix
a "Layout: …" node failedthe model wrote no usable slidestep 7: run it once more, then leave it out
"Logo del Brand" failednot an image Drive can read, or not sharedstep 7: unwire it and say so
"Anteprima dei Layout" failedthe deck could not be drawnstep 7a is skipped: say so at step 14; the master is not affected
"Anteprima del Master" failed, or "Crea il Master" has no previewthe preview deck could not be written or drawnstep 9a is skipped: say so at step 14; the master and the library are not affected
RENDER_FAILED ("Crea il Master")the deck could not be turned into a master (params.reason: not a Reveal deck, over 60 layouts, a slide with too many elements)fix what the reason names (fewer layouts, a simpler layout), run step 9 once more; then report
RENDER_SERVICE_UNAVAILABLE / LIBRARY_SERVICE_UNAVAILABLEdocument-render or the library service is downwait and run step 9 once more; then report
"Salva il Master" failedthe folder is missing or not writable by the userask for another folder; upsertNode its destinationFolder; run step 9 again
DUPLICATE_BRAND_MASTERa second Brand Master was added to this workspacedeleteNode the extra one (never the original)
UNSUPPORTED_MASTER_FILE (upload)the file is not a .pptx/.potx/.ppsxask for the right file; upsertNode "Brand Master" driveItemId
NO_SUPPORTED_LAYOUTSno layout of the master can take contentupload: the master must be fixed in PowerPoint; create: redesign the layouts (step 7)
RENDER_INCOMPLETEthe layouts' previews did not all renderrun "Brand Master" once more; then report
a layout is missing from layouts (step 10)it has two photos (unsupported), or it is turned offredesign it with one photo, or turn it on in curation
one layout misses part of the style, or differs from the otherseach layout applies the design on its ownmove that rule into the design's ```css block (every layout applies it, cleaned by the same rules), run step 7 and step 9 once more
the master's fonts look different in PowerPointthe font is not installed on that computeruse a font from the list in node-reference
"Crea il Master" layouts ≠ the wired pins of "Raccogli i Layout" after a layout was added or removeda pin is wired twice, or a run reused an old resultfix the wiring (one pin per "Layout: …" node) and run step 9 once more; still wrong → report the two numbers. NEVER change title, an instruction or any other input only to make a node run again: that changes the master

// Dependencies

requirements.py
1from input import DriveImageReader2from input import Text3from process import SlideGenerator4from process import MakeArray5from output import PresentationComposer6from process import Snapshot7from process import MasterFromSlides8from output import SaveFile9from process import BrandMaster

// Skills

Revisione Visivamarketplace/revisione-visiva@1.2.0

$ git log --oneline

v1.8.0
HEAD
2026-11-04
v1.7.02026-11-03
v1.6.02026-11-01
v1.5.02026-11-01
v1.4.02026-10-30
v1.3.02026-10-30
v1.2.02026-10-29
v1.0.02026-10-26