$ cat workspace-template.yaml

A

Analysis PMESII Version 3

// Sistema di analisi documentale PMESII versione 3 - A partire da un folder o un documento, esegue analisi di tipo Politico, Militare, Infrastrutturale, Informativo, Economico, Sociale e Ambientale.

Document Generation

// Canvas Preview

canvas.flow

// Instruction

instruction.md

PMESII Analysis (Macro)

Template ID

2ad81a2f-321c-4a1a-b597-01d49bcb0cf3

Overview

A PMESII intelligence-analysis pipeline, macro variant: each PMESII domain is ONE Macro Analysis [X] node (which bundles the Insert→Merge→Summarizer chain internally) fed by a Prompt PMESII [X] Text node, the shared Document Reader, and the Geopolitical Actor subject — its output goes to Make Array - Merge all Contentsave-file (one consolidated .md report). The template ships with one worked domain (one macro + one prompt, wired to item_0); the build expands it to the 7 PMESII domains (Political, Military, Economic, Social, Infrastructure, Information, Environmental). Public Share is optional and NEVER auto-run.

This is the same logical workflow as the chain-based pmesii-analysis.md, but a domain = 1 macro node + 1 prompt node (4 external edges) instead of a 3-node chain (6 edges).

The macro and its FIXED ports (critical)

Macro Analysis [X] (macro templateId 8739dcda-6f72-4ffe-8ba4-a71d6315ed45) exposes the same four port names on EVERY instance and clone — they are baked from the macro's origin and do NOT change per domain. The domain is set by the prompt you feed in and the node label, never by renaming ports. Use these exact strings when wiring any macro:

  • IN Summarizer_Environmental__contentDocument Reader [content]
  • IN Insert_The_Subject_into_Prompt_Environmental__text2Geopolitical Actor [value]
  • IN Analysis_prompt_Environmental__valuePrompt PMESII [X] [value]
  • OUT Summarizer_Environmental__summaryMake Array [item_<n>]

Workflow Chain

"Document Reader"[content] ─┐  (feeds every macro's ..._content port)"Geopolitical Actor"[value]─┤  (subject, feeds every macro's ..._text2 port)   Per domain X (×7):     "Prompt PMESII [X]"[value] → "Macro Analysis [X]"[..._Analysis_prompt..._value]     "Macro Analysis [X]"[..._summary] → "Make Array - Merge all Content"[item_n]"Make Array - Merge all Content"[items] → "save-file"[text]  → .md report (LOCAL — run this)                                        → "Public Share"[content] → public /s/{slug} (NEVER auto-run)

Domain → Prompt → Pin Mapping (IMMUTABLE, canonical order)

The existing example pair occupies item_0 (reconfigure it as row 1); rows 2–7 are built by cloning.

orderdomainprompt nodemacro nodepin
1PoliticalPrompt PMESII [Political]Macro Analysis [Political]item_0 (reuse existing)
2MilitaryPrompt PMESII [Military]Macro Analysis [Military]item_1
3EconomicPrompt PMESII [Economic]Macro Analysis [Economic]item_2
4SocialPrompt PMESII [Social]Macro Analysis [Social]item_3
5InfrastructurePrompt PMESII [Infrastructure]Macro Analysis [Infrastructure]item_4
6InformationPrompt PMESII [Information]Macro Analysis [Information]item_5
7EnvironmentalPrompt PMESII [Environmental]Macro Analysis [Environmental]item_6

Per-domain prompt text

Each Prompt PMESII [X] (a Text node, templateId 39023cd2-4e63-444c-ab58-57e6ba2ba8fb) gets value:

You are a military and intelligence analyst expert in the PMESII framework.
Analyze the provided document and produce a detailed PMESII analysis for the specified entity.
Analyze ONLY the **<DOMAIN>:** <focus>.
Use the document content to support your analysis. If certain information is not present in the document, explicitly state it.

Replace <DOMAIN> (uppercase) and <focus>:

  • POLITICAL — Political structure, leadership, government, stability, key decision-makers, political risks and opportunities.
  • MILITARY — Armed forces, capabilities, doctrine, threats, military alliances, defense spending, weapons systems.
  • ECONOMIC — Economy, resources, trade, dependencies, key industries, economic vulnerabilities, sanctions impact.
  • SOCIAL — Demographics, culture, society, social tensions, public opinion, ethnic/religious dynamics, migration patterns.
  • INFRASTRUCTURE — Critical infrastructure, transportation, communications, energy, water systems, ports, airports, digital infrastructure.
  • INFORMATION — Media, propaganda, information control, cyber capabilities, disinformation, intelligence services, information warfare.
  • ENVIRONMENTAL — Geographic factors, climate, natural resources, environmental threats, water scarcity, territorial disputes over resources.

Nodes the agent configures

  • "Document Reader"driveItemId = source document (single-file; no Drive Folder Reader in this template). Demo value present → replace.
  • "Geopolitical Actor" (Text) — value = subject. Demo = "Regia Marina" → replace.
  • "save-file"destinationFolder (REQUIRED; demo won't exist → 422), name = subject-based (see Phase 1). Terminal node — run it.
  • "Public Share" — optional public /s/{slug} link — NEVER auto-run.
  • Per domain: a Prompt PMESII [X] Text node + a Macro Analysis [X] macro node (built in Phase 2).

Execution Strategy

You MUST complete all 3 phases in order: Phase 1 → Phase 2 → Phase 3. Build the missing domains — never rebuild a domain that already exists.

Tool rule for inputs: the source file and the output folder are chosen with the Drive location picker selectDriveItem (the file/folder browser) — NOT with requestUserDecision/preset options. Only the subject (free text) uses requestUserDecision. Never ask the user to type or paste a Drive ID by hand.

Build with ATOMIC TOOLS ONLY — do NOT use generatePlan (or any plan/compile step). generatePlan FAILS on this build ("No object generated: response did not match schema") because of the macro nodes + the 7-domain fan-out. Build with upsertNode, cloneNodes, batchUpsertEdges directly, ONE domain at a time; no applyCanvasData after the initial commit.

Drive the tools yourself — do NOT punt to chat. Collect all three inputs by CALLING the tools in sequence within THIS turn (selectDriveItem for file → requestUserDecision for subject → selectDriveItem for folder), then continue to the build. The tools pause for the user on their own. Do NOT write a plain-chat message like "forniscimi il documento, il soggetto e la cartella" and end your turn — a prose question that stops the build is a FAILURE. Even when the user's request gives no file/subject/folder (e.g. just "crea un'analisi PMESII versione 3"), proceed straight into the pickers; never fall back to the demo file.

Fallback guard (CRITICAL) — applies to BOTH the source-file AND the output-folder question; they must behave identically: if you ask for a file/folder via requestUserDecision (e.g. selectDriveItem is unavailable), you MUST set allowFreeText: true so there is ALWAYS an open field where the user can type a name to search — then resolve it with searchDriveItems. Suggested files/folders may be added as options, but they are EXTRA choices, never the only ones, and keep them FEW (≤4 top matches) — the open field renders as the LAST option, so a long suggestion list buries it. NEVER allowFreeText: false for a file/folder question.

Phase 1: Source, Subject & Output

  1. applyCanvasDataIMMEDIATELY commit the template. Then use nodeFinder for all IDs.
  2. Source document — use the Drive file picker. Call selectDriveItem (type=file) so the user browses and picks the document — NOT a requestUserDecision with options, and never a hand-typed ID. (If the user already gave a file reference in chat, use it; otherwise open the picker — optionally searchDriveItems first to seed it.) Then nodeFinder → "Document Reader"; upsertNode { driveItemId: "<selected file ID>" }. Replaces the demo file.
  3. Subject. Call requestUserDecision once, free-text (options: []), key "subject": "Quale soggetto o entità geopolitica vuoi analizzare con il framework PMESII?" Read subject = answers.find(a=>a.key==="subject")?.otherText ?? ...selectedIds?.[0]. nodeFinder "Geopolitical Actor" → upsertNode { value: subject }.
  4. Output folder (REQUIRED) — use the Drive folder picker. Call selectDriveItem (type=folder) so the user browses and picks the destination folder. If you instead ask via requestUserDecision, it MUST have allowFreeText: true (an open field to type a folder name to search — then searchDriveItems it); you may add found folders as options, but NEVER allowFreeText: false. nodeFinder "save-file" → upsertNode { destinationFolder: "<picked folder ID>", name: "pmesii_<subject-slug>.md" }. Slugify the subject (lowercase, spaces/punctuation → hyphens), e.g. pmesii_regia-marina.md. The demo destinationFolder won't exist → 422, so always set a real, user-picked folder. (No date/time — the agent has no reliable clock; re-runs upsert the same item.)

Phase 1 complete. Now proceed to Phase 2.

Phase 2: Build the 7 domains

The macro's ports are ALWAYS ..._Environmental__... (see above) on every clone — use those exact strings; the domain comes from the prompt + label.

  1. nodeFinder → store the shared IDs reused by every domain: "Document Reader", "Geopolitical Actor", "Make Array - Merge all Content". Also nodeFinder → the existing macro ("Macro Analysis [Environmental]") and the existing prompt node (labelled "Prompt PMESII [Military]" but it actually holds the Environmental prompt) — store both IDs.

  2. Domain 1 (Political, item_0) — reconfigure the existing pair (do NOT clone for this one): a. upsertNode the existing macro → label: "Macro Analysis [Political]". b. upsertNode the existing prompt node → label: "Prompt PMESII [Political]", input: { value: "<POLITICAL prompt>" } (boilerplate above with the POLITICAL focus line). This fixes the mislabel and sets the right domain. c. Verify the existing wiring is intact (it ships wired): Document Reader→macro Summarizer_Environmental__content; Geopolitical Actor→macro Insert_The_Subject_into_Prompt_Environmental__text2; prompt→macro Analysis_prompt_Environmental__value; macro Summarizer_Environmental__summary→Make Array item_0. Re-assert any missing edge with upsertEdge.

  3. Domains 2–7 — For EACH domain X from item_1 to item_6 (Military, Economic, Social, Infrastructure, Information, Environmental), do a–d: a. Prompt node: upsertNode({ templateId: "39023cd2-4e63-444c-ab58-57e6ba2ba8fb", label: "Prompt PMESII [X]", input: { value: "<X prompt>" } }) (boilerplate + X's focus line). Store the new node id. b. Macro: cloneNodes({ nodeIds: ["<existing macro id>"] }) → returns nodeIdMap; the new macro id = nodeIdMap["<existing macro id>"]. Verify the clone exposes the four ..._Environmental__... ports. If cloneNodes cannot duplicate the macro, instead upsertNode({ templateId: "8739dcda-6f72-4ffe-8ba4-a71d6315ed45", label: "Macro Analysis [X]" }) to add a fresh macro. Either way upsertNode the new macro → label: "Macro Analysis [X]". c. Wire 4 edges (batchUpsertEdges), using the FIXED port names and the table's pin:

    • Document Reader[content] → macroX [Summarizer_Environmental__content]
    • Geopolitical Actor[value] → macroX [Insert_The_Subject_into_Prompt_Environmental__text2]
    • Prompt PMESII [X][value] → macroX [Analysis_prompt_Environmental__value]
    • macroX [Summarizer_Environmental__summary] → Make Array[item_<n>] (pin from table; NEVER item_0 — that's Political) d. Next domain.

    Hard gate: do NOT proceed to Phase 3 until all 7 domains exist (7 prompt nodes + 7 macros, each wired, on item_0…item_6).

  4. autoLayout() once to space the new nodes.

Phase 2 complete. Now proceed to Phase 3.

Phase 3: Verify & run

  1. nodeFinder → "Make Array - Merge all Content" and all 7 "Macro Analysis [X]". Verify against nodeFinder ground truth (a prior verification summary can be a false positive):
    • 7 distinct pins item_0…item_6, each fed by a different macro's Summarizer_Environmental__summary. item_0 = the Political macro. Empty pin / two macros on one pin → fix with upsertEdge.
    • Each macro has all three inputs wired (..._content, ..._text2, ..._value). A macro with no ..._value input has no prompt → empty analysis; fix with upsertEdge.
    • 7 prompt nodes exist, one per domain, each with the right domain focus in its value (not all the same domain).
    • "Document Reader" driveItemId = the user's file; "Geopolitical Actor" value = the subject (not "Regia Marina"); "save-file" destinationFolder set + name = pmesii_<slug>.md.
  2. nodeExecutor"save-file". Auto-resolves the whole upstream DAG. Wait for completion (no polling). Do NOT auto-run "Public Share".
  3. verification → checklist (info ✓ / warning / error): 7 macros wired, Make Array 7 pins, 7 distinct domain prompts, inputs set, save-file executed (report written, file name). Then followUp → summarize: 7 PMESII domains analyzed for "", report saved as .md; suggest next steps (change subject/source, "esegui Public Share per un link pubblico").

Phase 3 complete.

Configuration Tips

User saysConfigure
"cambia soggetto"upsertNode "Geopolitical Actor" { value }, then re-run "save-file".
"usa questo file" / "cambia documento"selectDriveItem (file) → upsertNode "Document Reader" { driveItemId }, then re-run.
"salva altrove"selectDriveItem (folder) → upsertNode "save-file" { destinationFolder }, then re-run.
"focalizza/aggiusta un dominio"edit that domain's Prompt PMESII [X] Text node value; do NOT touch the macro ports. Re-run "save-file".
"pubblica" / "link"nodeFinder "Public Share" → nodeExecutor. Warn: public /s/{slug} URL. Explicit request only.

Error Handling

  • Empty / wrong analysis for a domain: its Prompt PMESII [X]→macro Analysis_prompt_Environmental__value edge is missing, or the prompt holds the wrong domain. Re-wire / fix the prompt text.
  • A domain missing from the report: that macro's Summarizer_Environmental__summary → Make Array pin is missing — re-add with upsertEdge using the table pin.
  • save-file 422: source or output unset/invalid (often leftover demo values) — confirm "Document Reader" driveItemId and "save-file" destinationFolder are real, then re-run.
  • Tried to rename macro ports per domain: don't — every macro keeps the ..._Environmental__... ports; wire to those exact names. Domain identity = prompt + label.
  • cloneNodes didn't duplicate the macro: add a fresh macro from templateId 8739dcda-… instead (Phase 2 step 7b), then wire normally.
  • Folder question had no open field: never allowFreeText: false for a file/folder; use selectDriveItem or requestUserDecision with allowFreeText: true + ≤4 options.

Incremental Edits

If the 7 macros + a wired Make Array already pre-existed this turn, it's an EDIT: do NOT re-applyCanvasData or re-run the build. Apply the delta (change subject/source: upsertNode → re-run "save-file"; add/remove a domain: create/clone or delete the macro+prompt and fix the Make Array pin order), re-run the Phase 3 verification + "save-file". Public Share only on explicit request.

Cross-references

pmesii-analysis.md (the chain-based equivalent) · reference/INSTRUCTION_GUIDELINES.md.

// Dependencies

requirements.py
1from macro import MacroAnalysisTYPE2from input import DriveDocumentReader3from input import Text4from output import PublicShare5from process import MakeArray6from output import SaveFile

$ git log --oneline

v1.0.4
HEAD
2026-06-27
v1.0.32026-06-27
v1.0.22026-06-27
v1.0.12026-06-27
v1.0.02026-06-27