Guest Access for Canvas and Model-Driven Apps with Microsoft Entra ID
July 2, 2026Exam AI-901 Study Guide: Microsoft Azure AI Fundamentals
July 2, 2026Part 5 of 5.
Across this series the game has reasoned about a founder, designed a digital workforce for their venture, executed chapters through Microsoft Foundry agents, and gated every artifact behind a human. That is a complete loop – inside the game. This final post is about the seam where it leaves the game: how the Org Designer‘s output becomes a portable artifact a real digital-worker platform can ingest and provision, without dragging a single proprietary dependency into the public repo.
The most useful thing a reasoning agent can produce is not a paragraph. It is a structured plan another system can execute – behind its own human gate.
Why the Org Designer is the keystone worker
In Part 1 the pipeline’s second stage was the Org Designer: given a venture, it designs the smallest org that can actually deliver it – one human operator plus the digital workers that form the execution layer. Every other system in the game hangs off that output. The World Designer decomposes the venture into chapters; bind_world_to_org stamps each chapter with its owning worker; the economy prices each worker’s monthly burn. The org the model designs is the org that executes.
You can see the artifact directly in play – a worker delivers a positioning brief and a rendered org chart, and it passes the gate:
A worker delivers a rendered org chart that passes the verification gate
That org chart is not decoration. It is structured state – roles, kinds (human / digital_worker / hybrid), mandates, reporting lines, KPIs, tool wishes, and a model-class hint per worker. Which means it can be exported.
The org being exported: OrgRole and OrgBlueprint
To understand the bundle you have to see the state it is built from. The org is an OrgBlueprint in submission/state/schema.py – a company summary, an operating model, and a list of OrgRole seats. Each role is a typed record, not a sentence:
# submission/state/schema.py
class OrgRole(BaseModel):
id: str
title: str
kind: str = “digital_worker” # human | digital_worker | hybrid
mandate: str = “” # what this seat is accountable for
reports_to: Optional[str] = None
kpis: List[str] = Field(default_factory=list)
tools: List[str] = Field(default_factory=list)
deployment_hint: str = “” # which model class fits this worker
lifecycle_stage: str = “” # discovery|positioning|mvp|gtm|retention|ops
monthly_cost_usd: int = 0 # the worker’s monthly wage (the burn)
why: str = “” # why this seat must exist
Because every field is structured, the converter has something real to map – it is not parsing prose back into fields, it is re-shaping records it already trusts. kind becomes the human/digital split; deployment_hint becomes the portable model_class; reports_to becomes the org chart’s edges; mandate, kpis, and tools become the worker’s brief. The blueprint also carries derived economics (monthly_burn_usd, leverage_ratio, monthly_savings_usd) that ride into the bundle unchanged.
How the org gets designed
That blueprint is itself the output of a Foundry agent. design_org in submission/agents/org_designer.py runs on the org-designer deployment (a stronger model, because it shapes the whole run), asks for a structured roster, and parses it through the same tolerant _extract_json from Part 2 – falling back to a deterministic blueprint when there are no credentials:
= 2:
return _finalize(parsed, brief, source, source_ref, summary_hint)
return _finalize(_fallback_blueprint(brief), brief, source, source_ref, summary_hint)
“># submission/agents/org_designer.py
def design_org(brief, source=”pitch”, source_ref=””, summary_hint=””):
client = get_foundry_client()
deployment = model_for(“orgdesigner”) or model_for(“narrator”)
if not (client and deployment and is_live()):
return _finalize(_fallback_blueprint(brief), brief, source, source_ref, summary_hint)
resp = create_chat_completion(deployment, […], max_completion_tokens=8000)
parsed = _extract_json(resp.choices[0].message.content or “”)
if parsed and len(parsed.get(“roles”, [])) >= 2:
return _finalize(parsed, brief, source, source_ref, summary_hint)
return _finalize(_fallback_blueprint(brief), brief, source, source_ref, summary_hint)
_finalize is where the model’s creative roster meets deterministic mechanics: it normalises every role, prices each seat, and computes the headline stats. The model decides who the company needs; the code decides what they cost. That division – which we have now seen at the gate (Part 2), in consequences (Part 3), and here – is the spine of the whole project, and it is why an exported bundle’s economics are trustworthy even though a model drew the org.
The org binds to the quest
The designed org does not sit in a corner – it is stamped onto the quest line. bind_world_to_org in worker_factory.py walks the stages and assigns each one the digital worker whose lifecycle stage matches, so every chapter has an owning worker before play begins:
# submission/agents/worker_factory.py
def bind_world_to_org(world, org):
bindings = {}
for stage in world.stages:
worker = _match_worker_for_stage(stage, org)
if worker:
stage.assigned_worker_id = worker.id
stage.assigned_worker_title = worker.title
bindings[stage.id] = worker.title
return bindings
This is why the export is meaningful: the org in the bundle is the same org that executed the run. The worker that owns the GTM chapter in the game is the worker the bundle hands the receiving platform for GTM. Nothing is invented at export time.
The bridge: export, don’t import
The temptation, when you have a game and a real platform, is to wire them together – run the platform’s workers inside the game. That is the wrong move for two reasons. First, the game’s reasoning core must stay 100% Microsoft Foundry (the rubric rule, and the architectural spine of this series). Second, the repo must run after git clone with no proprietary dependencies. So the bridge is export, not import: the game emits a neutral bundle; any platform ingests it.
Foundry gpt-5 family]
B –> C[OrgBlueprint
in game state]
C –> D[GET /api/org/export
workforce_bundle.json]
D –> E[Any digital-worker platform
maps + reviews]
E –> F[Human approval gate]
F –> G[Provisioned workers,
teams, KPIs, workflows]
–>
No platform-specific code lives in the game repo. The converter is pure and offline – it turns the in-game OrgBlueprint into a platform-neutral workforce_bundle and ships a CLI that runs in simulation after a fresh clone.
The converter is pure and offline
The module that does the work, submission/tools/export_org_blueprint.py, is deliberately dependency-free: no platform SDK, no network, no credentials. It splits the chartered roles into humans and digital workers and emits one spec per worker:
# submission/tools/export_org_blueprint.py
def org_to_workforce_bundle(org):
roles = org.get(“roles”) or []
humans = [r for r in roles if r.get(“kind”) == “human”]
workers = [r for r in roles if r.get(“kind”) != “human”]
worker_specs = [{
“worker_key”: _slug(role.get(“id”) or role.get(“title”, “”)),
“name”: role.get(“title”, “Digital Worker”),
“kind”: role.get(“kind”, “digital_worker”),
“system_message”: _system_message(role, org),
“model_class”: _MODEL_CLASS.get(role.get(“deployment_hint”, “”), “fast”),
“tools”: role.get(“tools”) or [], “kpis”: role.get(“kpis”) or [],
“reports_to”: _slug(role.get(“reports_to”) or “”),
# … seniority, monthly_cost_usd, why …
} for role in workers]
# … company, economics, team, provisioning …
Because it is pure, the same function backs both the live HTTP endpoint and a no-server CLI, and it runs in simulation after a fresh clone – the export is forkable like everything else in this series.
The bundle: a contract, not a dump
The export is a single JSON document with a stable format tag (campaign.workforce_bundle, versioned), designed so both a human approver and a downstream LLM can parse and act on it:
<PRE class="language-json" tabindex="0" contenteditable="false" data-lia-code-value="{
"format": "campaign.workforce_bundle",
"version": 1,
"company": { "summary": "…", "operating_model": "…", "source": "pitch" },
"economics": { "headcount": 6, "digital_worker_count": 5,
"human_count": 1, "monthly_burn_usd": 23625, "leverage_ratio": 5.0 },
"team": { "name": "…", "purpose": "…", "members": ["…"], "owner": "operator" },
"humans": [ { "id": "operator", "title": "Founder / Operator", "mandate": "…", "kpis": ["…"] } ],
"workers": [
{
"worker_key": "strategy_positioning_lead",
"name": "Strategy & Positioning Lead",
"role": "strategist",
"kind": "digital_worker",
"system_message": "…generated starter prompt…”,
“model_class”: “reasoning”,
“tools”: [“…”], “kpis”: [“…”], “reports_to”: “operator”
}
],
“org_chart_mermaid”: “graph TDn …”,
“provisioning”: {
“status”: “pending_human_approval”,
“note”: “Nothing in this bundle is provisioned. The receiving platform must
present it for explicit human approval before creating anything.”
}
}
“>
{
“format”: “campaign.workforce_bundle”,
“version”: 1,
“company”: { “summary”: “…”, “operating_model”: “…”, “source”: “pitch” },
“economics”: { “headcount”: 6, “digital_worker_count”: 5,
“human_count”: 1, “monthly_burn_usd”: 23625, “leverage_ratio”: 5.0 },
“team”: { “name”: “…”, “purpose”: “…”, “members”: [“…”], “owner”: “operator” },
“humans”: [ { “id”: “operator”, “title”: “Founder / Operator”, “mandate”: “…”, “kpis”: [“…”] } ],
“workers”: [
{
“worker_key”: “strategy_positioning_lead”,
“name”: “Strategy & Positioning Lead”,
“role”: “strategist”,
“kind”: “digital_worker”,
“system_message”: “…generated starter prompt…”,
“model_class”: “reasoning”,
“tools”: [“…”], “kpis”: [“…”], “reports_to”: “operator”
}
],
“org_chart_mermaid”: “graph TDn …”,
“provisioning”: {
“status”: “pending_human_approval”,
“note”: “Nothing in this bundle is provisioned. The receiving platform must
present it for explicit human approval before creating anything.”
}
}
Three design choices make it portable:
- A generated
system_messageper worker, same shape for every role – so a receiving platform (or its own org-architect agent) can parse, refine, and version it instead of re-deriving prompts. - A
model_classhint (reasoning/fast/creative), not a hard model name – the receiver maps it onto its own fleet. - A
provisioning.statusofpending_human_approvalbaked into the artifact itself. The bundle carries its own gate: the game’s verification-gate pattern (Part 2), extended across the system boundary.
CONV –> B[“workforce_bundle.json”]
B –> CO[“company + economics”]
B –> HU[“humans[] (operator)”]
B –> WK[“workers[]
system_message, model_class,
tools, kpis, reports_to”]
B –> MM[“org_chart_mermaid”]
B –> PV[“provisioning.status =
pending_human_approval”]
–>
Every worker carries its own starter prompt
The single most portable field is system_message. Every worker – whatever its role – gets a generated starter prompt in the same XML shape, so a receiving platform (or its own org-architect agent) can parse, refine, and version it instead of re-deriving prompts from scratch:
<PRE class="language-python" tabindex="0" contenteditable="false" data-lia-code-value="# submission/tools/export_org_blueprint.py – _system_message
return (
f"n”
f” {role.get(‘title’)}n”
f” {role.get(‘mandate’, ”)}n”
f” {reports_to}n”
f” {kpis}n”
f” n”
f” – Work only within this mandate; escalate judgment calls to {reports_to}.n”
f” – No legal or financial commitments without explicit human approval.n”
f” n”
f””
)
“>
# submission/tools/export_org_blueprint.py – _system_message
return (
f”n”
f” {role.get(‘title’)}n”
f” {role.get(‘mandate’, ”)}n”
f” {reports_to}n”
f” {kpis}n”
f” n”
f” – Work only within this mandate; escalate judgment calls to {reports_to}.n”
f” – No legal or financial commitments without explicit human approval.n”
f” n”
f””
)
Those guardrails are not decoration. Every exported worker ships with “no legal or financial commitments without explicit human approval” baked into its own identity – the human gate is written into the worker’s prompt, not just the bundle’s status field.
The org chart travels as text
There is a fitting symmetry with this whole series, which has leaned on Mermaid for every diagram: the bundle ships the org chart as Mermaid source, generated by org_to_mermaid. A receiver can render it, diff it, or hand it to a model – it is text, not a picture:
n_{_slug(role[‘id’])}”)
“># submission/tools/export_org_blueprint.py – org_to_mermaid
lines = [“graph TD”]
lines.append(” classDef human fill:#f6d55c,stroke:#5b8cff,stroke-width:3px”)
lines.append(” classDef digital fill:#3caea3,stroke:#2dd4bf”)
for role in roles:
cls = “human” if role[“kind”] == “human” else “digital”
lines.append(f’ n_{_slug(role[“id”])}[“{title}”]:::{cls}’)
for role in roles: # reporting lines
if role.get(“reports_to”):
lines.append(f” n_{_slug(role[‘reports_to’])} –> n_{_slug(role[‘id’])}”)
Humans and digital workers get different CSS classes, so the rendered chart shows at a glance who is a person and who is a digital worker – the same human/digital distinction the economics priced, carried into the picture.
The economics travel with the org
A workforce plan that does not say what it costs is a wish list. The bundle carries an economics block – headcount, digital-worker count, human count, monthly burn, and a leverage ratio – computed by the game’s worker_economics model when the org was designed, not invented at export time:
“economics”: {
“headcount”: 6, “digital_worker_count”: 5, “human_count”: 1,
“monthly_burn_usd”: 23625, “monthly_inference_usd”: 1200, “leverage_ratio”: 5.0
}
Each worker also carries its own monthly_cost_usd, so a receiving platform can show a real budget before it provisions anything – one human operator leveraging five digital workers at a burn a solo founder could actually carry. That leverage ratio (digital workers per human) is the headline number the whole game is about: how much execution one person can direct. Exporting it means the off-ramp inherits the argument, not just the boxes and arrows.
Pricing the workforce
Those numbers are not vibes. submission/agents/worker_economics.py prices each seat from the human salary it replaces – a deliberate game-balance fraction, so burn is a constraint the player actually feels rather than a rounding error:
# submission/agents/worker_economics.py
WORKER_COST_FRACTION_OF_HUMAN = 0.75 # a worker costs 3/4 of the human it replaces
def worker_cost_from_human(human_median_usd):
return int(round(max(0, human_median_usd) * WORKER_COST_FRACTION_OF_HUMAN))
Each worker’s monthly_cost_usd is three quarters of the present-world salary for that seat; the much cheaper real compute (inference_usd) is tracked separately for the efficiency story. Sum the workers and you get monthly_burn_usd; divide digital workers by human operators and you get leverage_ratio. When a receiving platform reads the bundle, those are the figures it shows before provisioning – a real budget for one operator running a digital team, derived the same way whether the org was designed on Foundry or in simulation.
The export endpoint and the button
The bridge is one endpoint and one button. GET /api/org/export reads the chartered org from state, converts it, logs an ORG_EXPORTED event to the replay log (Part 4), and returns the bundle as a download. The Digital Workforce panel in the UI has an Export workforce bundle button that calls it – so “you played the game; now your org is a deployable workforce” is one click.
@app.get(“/api/org/export”)
def export_org():
state = store.load()
if not state.org or not state.org.roles:
raise HTTPException(status_code=404, detail=”No chartered org to export.”)
bundle = org_to_workforce_bundle(state.org.model_dump())
store.log_event(“ORG_EXPORTED”, “org_designer”,
f”Exported {len(bundle[‘workers’])} workers, pending approval.”)
return JSONResponse(content=bundle,
headers={“Content-Disposition”: ‘attachment; filename=”workforce_bundle.json”‘})
Because the converter is dependency-free, it also runs from the command line with no server and no credentials:
workforce_bundle.json : 5 digital workers + 1 human, pending approval
“>python3 submission/tools/export_org_blueprint.py
–pitch “Low-cost 3D-printed solar cells for off-grid homes”
# -> workforce_bundle.json : 5 digital workers + 1 human, pending approval
The CLI: same converter, no server
Because the converter is pure, the same org_to_workforce_bundle function powers a no-server CLI – export_org_blueprint.py – which can either read a saved game state or design a fresh org from a pitch and export it, all in simulation, no credentials:
# submission/tools/export_org_blueprint.py – _main
if args.pitch:
from agents.org_designer import design_org
org = design_org(args.pitch, source=”pitch”, source_ref=args.pitch)
else:
org = json.load(open(state_path)).get(“org”) or {} # from a played game
bundle = org_to_workforce_bundle(org)
print(json.dumps(bundle, indent=2))
That one entry point is the whole forkability story for the bridge: –pitch “…” designs an org and prints a deployable workforce bundle on a fresh clone, with no Azure, no server, and no platform SDK anywhere in the path. The endpoint and the CLI share the exact same converter, so what you can click in the live app you can also pipe in a shell.
Best practice: the receiver re-gates, the bundle is a draft
A portable bundle is an input, not an order. On the receiving side, the right pattern is an org-architect worker that treats the bundle as a draft blueprint: it maps each entry’s model_class onto the platform’s current model tiers, matches incoming worker mandates against existing templates (reuse before invent), re-renders the org chart in its own conventions, fills gaps the game did not model (departments, OKR cascades), and then presents the result for explicit human approval – exactly the CEO-gate pattern, one system later.
That symmetry is the point. The game gates artifacts behind a human; the bundle declares itself pending; the receiver gates provisioning behind a human. The human-at-the-root law (Part 2) survives the trip across the boundary.
flowchart LR
G1["Game CEO gate
(Part 2)”] –> B[“bundle:
pending_human_approval”]
B –> RCV[“Receiving platform
org-architect worker”]
RCV –> MAP[“map model_class -> fleet
reuse templates, fill gaps”]
MAP –> G2[“Receiver human gate”]
G2 –> PROV[“provision workers,
teams, KPIs”]
–>
Why this matters beyond the game
A reasoning agent that only produces prose is a better chatbot. A reasoning agent that produces a structured, portable, gated plan another system can execute is the beginning of an operating loop. The game is a teaching tool and a playable argument; the bundle is the off-ramp where the argument becomes useful – the designed workforce stops being a screen and becomes something a platform can stand up, behind its own approval gate.
Responsible AI
The bundle is inert by construction. Its provisioning.status is pending_human_approval and its note says, in the artifact itself, that nothing is provisioned until a human signs off. Nothing in it is executable on import; it is a description, not a command. Combined with the receiver re-gating provisioning, that means no chain of automated steps can stand up a workforce without a person in the loop – the same reliability story this whole series is built on, carried one boundary further.
The whole series, in one artifact
It is worth seeing the bundle as the place every earlier post converges. The org inside it was decomposed from a pitch (Part 1) and designed on a Foundry model. Every artifact that filled it out passed a human verification gate (Part 2). The CEO decisions that shaped which workers exist are the binding memory the workforce learned from (Part 3). The whole thing was produced by a stack that runs local-first and fully traced, so the ORG_EXPORTED event sits in the same replay log as everything that led to it (Part 4). And now it leaves the game as a portable, gated plan (Part 5). The bundle is not a feature bolted on at the end; it is the receipt for the entire loop.
Where this lives in the repo
| Concern | File | Key symbol |
|---|---|---|
| Pure offline converter + CLI | submission/tools/export_org_blueprint.py |
org_to_workforce_bundle, _system_message, org_to_mermaid |
| Export endpoint + replay event | submission/tools/server.py |
GET /api/org/export, ORG_EXPORTED |
| The org being exported | submission/agents/org_designer.py |
design_org, OrgBlueprint |
Try it
Charter an org in the game, then export it:
Play the live app -> design your workforce -> Export workforce bundle.
Or from the CLI, no credentials:
git clone https://github.com/princepspolycap/agentsleague-afterbuild
cd agentsleague-afterbuild && python3 -m venv .venv && source .venv/bin/activate
pip install -r submission/requirements.txt
python3 submission/tools/export_org_blueprint.py –pitch “Your idea here”
Key takeaways
- The most useful agent output is a structured plan another system can execute, not prose.
- Bridge by export, not import: emit a neutral, versioned bundle; keep proprietary platforms out of the reasoning repo.
- Carry the human gate across the boundary – the bundle declares itself
pending_human_approval, and the receiver re-gates provisioning. - Use a
model_classhint, not a hard model name, so the receiver maps onto its own fleet. - One endpoint, one button: “you played the game; now your org is a deployable workforce.”
The dungeon is open, the workforce is designed, and now it is portable. A mission too big to command gets aligned one company at a time – and the org you charter in a browser game can walk out as a plan a real platform will run, with a human still holding the seal.
Part 5 of 5. Start over at Part 1, or clone the repo and pitch your own company.
- Play it: worldforge-game…azurecontainerapps.io
- Code: github.com/princepspolycap/agentsleague-afterbuild
- Live battle replay: Agents League – Reasoning Agents