This file consolidates everything the published docs don't make obvious — the rules that bite during build/edit. When in doubt about a field name or shape, mirror canonical-example.md.
GA is built on A2A v1.0 and stays backward-compatible with A2A v0.3 clients via the a2a_v03 registry branch. Beta patterns (metadata.protocol + flat metadata.card, kind: "a2a:response" echo with nested task: a2a.task({...}), policies as flat array) no longer apply.
my-agent-network-project/
├── agent-network.yaml # registry + context + brokers
├── exchange.json # Anypoint Exchange asset metadata + variables
└── brokers/
└── <broker-id>.agent # Agent Script — one graph per file
For multi-broker projects: one .agent per broker, each referenced from its own entry under brokers:.
agentNetwork: 2.0.0— unquoted. (V1 usedschemaVersion: 1.0.0.)exchange.json"classifier": "agentic-network". (V1 usedagent-network.)info.versionaccepts non-semver strings (v1works in canonical).
GA places the agent card under metadata.interfaces.<branch>.card where <branch> is one of:
a2a— current A2A v1.0 card. Use this for agents on v1.0.a2a_v03— legacy A2A v0.3 card. Use this for agents that haven't migrated; the broker still talks to them transparently.other— non-A2A interfaces (custom HTTP, etc.).
registry:
agents:
helpCenterAgent:
info:
label: Help Center Agent
metadata:
platform: Other
interfaces:
a2a_v03: # legacy v0.3 agent
card:
name: Help Center Agent
description: ...
url: http://localhost:8080/helpCenterAgent
protocolVersion: 0.3.0
version: 1.0.0
capabilities: { pushNotifications: false }
defaultInputModes: [application/json, text/plain]
defaultOutputModes: [application/json, text/plain]
skills: [...]The Beta combination of metadata.protocol: a2a + flat metadata.card.<branch> is removed. Don't emit it.
| Field | a2a (v1.0) |
a2a_v03 (legacy) |
|---|---|---|
url |
Required (per A2A v1.0 spec) | Required |
protocolVersion |
Required | 0.3.0 |
version, capabilities, defaultInputModes, defaultOutputModes, skills |
Required | Required |
Broker card exception: a broker IS the endpoint, so its own card under brokers.<id>.interfaces.a2a.card typically omits url and protocolVersion (the runtime fills them in at deploy). The required-field rules apply to registry agent cards (external agents the broker calls). When in doubt for a broker, mirror canonical-example.md.
# @dialect: AGENTFABRIC=1.0
AGENTFABRIC=1.0 pins to dialect 1.0 or later within the major. Major-only (AGENTFABRIC=1) references the latest within that major. Patch fixes (AGENTFABRIC=1.0.2) are invalid; major-or-major.minor only.
config:
agent_name: "it-help-investigation" # optional, conventionally kebab-case
default_llm: @llm.openai_mini # optional
agent_name is optional per the schema. When present, use kebab-case matching the .agent filename stem (the docs' canonical convention) — a human-readable quoted string with spaces also validates but the kebab convention is what the IT example uses. label and description are optional. Do NOT add name or id.
Exact case: "Gemini" or "OpenAI". Azure OpenAI deployments use kind: "OpenAI" in the .agent LLM block; AzureOpenai only appears at registry.llms.<id>.metadata.platform.
These bite the most.
Definition: only target and kind. NO inputs:. A2A tools accept only a message parameter (plain string).
actions:
help_center_agent:
target: "a2a://help_center_agent_connection"
kind: "a2a:send_message"
Inside subagent/orchestrator reasoning.actions: bare reference. Adding with message = ... is a compile error. The LLM picks the message at runtime.
reasoning:
actions:
search_help: @actions.help_center_agent # ✓ bare reference
# search_help: @actions.help_center_agent
# with message = "..." # ✗ COMPILE ERROR
Inside executor do: run: REQUIRES with message = <value> where <value> is string literal, @reference, or concatenation.
do: ->
run @actions.help_center_agent
with message = "Search for: " + @generator.classify.output.topic
Definition: target, kind: "mcp:tool", tool_name, optional inputs:. Only declare inputs: if you actually know the parameter names and types.
actions:
escalate_ticket:
target: "mcp://escalation_mcp_connection"
kind: "mcp:tool"
tool_name: "escalate"
inputs:
ticket_id: string
severity: string
with parameters must be declared in inputs: — passing an undeclared with parameter is a compile error. If inputs: is omitted, the runtime auto-discovers tool arguments and the invocation MUST have zero with parameters (other than http_headers).
Slot-fill (...) is only valid inside reasoning.actions MCP with clauses. Never in executor run.
reasoning:
actions:
update_ticket: @actions.update_jira_ticket
with ticket_id = @generator.classify.output.ticket_id # ✓ declared input
with http_headers = {"Authorization": @request.headers["Authorization"]} # ✓ implicit
send_slack: @actions.send_slack_message
with message = ... # ✓ slot-fill (MCP only)
Every action automatically accepts an optional http_headers parameter (an object). Never declare in inputs:. Use to propagate auth or correlation IDs.
- Trigger
on_message:must be a fixedtransition to. Conditional routing insideon_message:is a compile error — use arouternode. - Router
on_exit:withtransition tois a compile error. Routers transition exclusively viaroutesandotherwise. a2a.message/a2a.artifact/a2a.textPart/a2a.dataPart/a2a.filePart/uuid()are FUNCTIONS, not references — do NOT prefix with@.
GA echo replaces the Beta kind: "a2a:response" (with nested task: a2a.task({...})) with A2A v1.0 update events. Two kind values:
| Kind | Required parameters | Optional parameters |
|---|---|---|
a2a:status_update_event |
state (string), message (built via a2a.message(...)) |
metadata (dict) |
a2a:artifact_update_event |
artifact (built via a2a.artifact(...)) |
append (bool), lastChunk (bool) |
Status update example (GA):
echo escalationResponse:
kind: "a2a:status_update_event"
state: "TASK_STATE_COMPLETED"
message: a2a.message({
messageId: uuid(),
parts: [
a2a.textPart("Ticket " + @generator.classifySeverity.output.ticket_id + " escalated.")
]
})
Artifact update example:
echo addArtifact:
kind: "a2a:artifact_update_event"
artifact: a2a.artifact({
artifactId: uuid(),
name: "myArtifact",
parts: [
a2a.textPart("Employee ID: " + @orchestrator.hrSystemOnboard.output.employeeId)
]
})
append: false
lastChunk: false
Echo state enum. GA emits TASK_STATE_* constants (uppercase, prefixed). One of:
TASK_STATE_SUBMITTED, TASK_STATE_WORKING, TASK_STATE_INPUT_REQUIRED, TASK_STATE_COMPLETED, TASK_STATE_FAILED, TASK_STATE_CANCELED, TASK_STATE_REJECTED. Custom values are rejected.
No a2a.task(...) wrapper. GA echo doesn't wrap its payload in a2a.task({...}). Build status updates with state: "..." + message: a2a.message(...) directly. The runtime aggregates events into the canonical Task on the server side.
| Form | Where | Example |
|---|---|---|
{!@<reference>} |
Inside plain string literals (prompt:, reasoning.instructions:) |
"Severity is {!@generator.classify.output.severity}" |
Direct @reference |
Inside + concatenation, in with values, inside a2a.*() echo helpers |
"Ticket " + @generator.classify.output.ticket_id |
Slot-fill ... |
reasoning.actions MCP with clauses ONLY |
with message = ... |
Inside echo a2a.message() / a2a.artifact() / a2a.textPart(), references are direct. {!@...} does NOT apply inside echo helpers.
Does this node use any actions OR require human-in-the-loop?
├─ NO → generator (single LLM call, no actions, no HITL)
└─ YES
└─ Does this node coordinate MULTIPLE actions toward a compound goal?
├─ YES → orchestrator
└─ NO → subagent (default)
Single-action node calling one A2A agent → subagent. NOT orchestrator. Node type is determined by coordination scope, not protocol.
subagent and orchestrator MUST have ≥1 action OR HITL. Otherwise use generator.
HITL is built into subagent via the runtime's input-required A2A response. Don't model clarification as an external subagent → router on needs_clarification → executor → echo flow.
Two optional fields on every subagent/orchestrator:
reasoning.max_number_of_loops— caps the agent loop. Default 25. Lower for tight loops: classification subagents fine at 3, multi-action orchestrators usually 5–10. Default 25 risks runaway token spend on bad inputs.reasoning.task_timeout_secs— wall-clock cap. No documented default; set when calling slow downstream agents.
orchestrator crossPlatformTriage:
reasoning:
instructions: -> | {!@request.payload.message.parts[0].text}
actions: { ... }
max_number_of_loops: 5
task_timeout_secs: 60
generator: at node top level (sibling ofprompt:).subagent/orchestrator: nested insidereasoning:(sibling ofreasoning.instructionsandreasoning.actions).
Wrong placement is a compile error.
-
urlis optional for all connection kinds (a2a, mcp, llm). Resolved at deploy time when omitted. -
authenticationis required forkind: llmconnections, optional fora2aandmcp. -
policieson a connection (when present) is an object withinboundandoutboundarrays:context: connections: my_connection: kind: a2a ref: { name: myAgent } url: ${myAgent.url} policies: inbound: [] outbound: - ref: { name: rate-limit-policy }
The Beta shape (flat array of policy ids) is removed.
| Auth kind | Casing |
|---|---|
| API key | apiKey |
| API key client credentials | apikey-client-credentials |
| OAuth2 client credentials | oauth2-client-credentials |
| OAuth2 OBO | oauth2-obo |
| Basic auth | basic |
| In-task authorization code | in-task-authorization-code |
Default to apiKey, oauth2-client-credentials, oauth2-obo. in-task-authorization-code is for OAuth2 step-up — don't emit unless explicitly requested.
GA additions:
distributedfield onoauth2-oboandin-task-authorization-codeblocks (boolean) — set when the auth flow spans services or replicas.in-task-authorization-codeacceptssubjectTokenTypeandrequestedTokenType(token-exchange semantics).
variables:
response_message: string
response_state: string
- Only declare for cross-path shared state (e.g.,
response_messagewritten by multiple paths and read by a shared echo). - Do NOT mirror node outputs (
@<nodeType>.<nodeId>.output) or globally-accessible request data — reference directly. - Never declare a variable that isn't both set and read by ≥1 node.
- Syntax:
<name>: <type>with optional indenteddescription:. NOmutable, NO defaults like= "".
Always look up current production model IDs at provider docs:
- Gemini: https://ai.google.dev/gemini-api/docs/models
- OpenAI: https://developers.openai.com/api/docs/models
GA-supported families: GPT-5 family (OpenAI / Azure OpenAI) and Gemini 2.5 / 3 family. When emitting model IDs, confirm with the user — IDs change quickly across releases.
Every asset is in one of two modes. Each asset's mode is independent — a single project can mix.
Used when the asset doesn't exist in Anypoint Exchange.
Two places:
- a)
registry.{agents,mcps,llms}.<id>— asset definition. - b)
context.connections.<connId>withref.name: <id>matching the registry id.
No exchange.json.dependencies entry. No ref.namespace.
Used when the asset exists in Anypoint Exchange — Private (your org) or Public.
Two places:
- a)
exchange.json.dependencies—{ groupId, assetId, version, classifier, packaging: "zip" }. - b)
context.connections.<connId>withref.name: <assetId>ANDref.namespace: <groupId>. No registry entry.
| Need | Asset type |
|---|---|
| Delegate to another autonomous agent that owns its logic | A2A agent |
| Call a specific API/function | MCP server tool |
| Classify, summarize, generate, judge | LLM |
Prefer MCP for single API calls (cheaper, faster). Prefer A2A for multi-step delegation (autonomous reasoning).
If search_asset is available, call it per asset need. Search Private Exchange first; only fall back to Public if Private has no match. Confirm before pulling Public.
| Asset type | assetFilters |
|---|---|
| LLM | ["llm"] |
| MCP server | ["mcp"] |
| A2A agent | ["agent"] |
If search_asset isn't available, ask: "Do you have this in Exchange already, or should I register a placeholder?"
search_asset → found in Private? → Case A (Exchange, Private)
→ found only in Public? → Case B (confirm, then Exchange, Public)
→ not found anywhere? → Case C (inline placeholder)
Case C placeholder: create a registry entry with default: "" for URLs/secrets in exchange.json. Flag clearly. Example:
registry:
agents:
customAgent:
info:
label: Custom Agent (PLACEHOLDER — fill in skills)
metadata:
platform: Other
interfaces:
a2a:
card:
name: customAgent
description: TODO
url: ${customAgent.url}
protocolVersion: "1.0"
version: 1.0.0
capabilities: { pushNotifications: false }
defaultInputModes: [application/json, text/plain]
defaultOutputModes: [application/json, text/plain]
skills: []When you finish the build, list every placeholder explicitly. Never fabricate asset IDs, URLs, or MCP tool names.
Per asset, atomically:
- Inline OR Exchange definition (per RULE-ASSET-MODE).
- Add any new
${...}variables toexchange.json.metadata.variables. Mark URLssecret: false. API keys / passwords / OAuth secretssecret: true. - Confirm with user before next asset.
Naming conventions (from canonical + YAML reference):
- Registry asset id (agents/mcps/llms): camelCase or kebab-case. Schema allows
^[a-zA-Z_][a-zA-Z0-9_.-]*$. The IT example uses camelCase (helpCenterAgent,escalationMcp,openAiMini). - Connection id: any valid YAML identifier. There is no snake_case-only schema restriction — camelCase, snake_case, and kebab-case all validate. The canonical example uses snake_case (
help_center_agent_connection) for readability, but that's a convention, not a rule. The one hard requirement: the id must match the.agenttarget exactly (see Trigger/target rules below). - Broker id (key under
brokers:): same — any valid YAML identifier; no snake_case-only restriction.it_help_investigation,it-help-investigation, anditHelpInvestigationall validate. The.agentfilename is independent (kebab-case is fine —it-help-investigation.agent). The only hard rule: the triggertarget: "brokers://<broker-id>/a2a"must match the YAML key exactly. - Trigger
target::brokers://<broker-id>/a2awhere<broker-id>matches the YAML key exactly. If the broker id has underscores, the trigger target does too. - Variables (in
exchange.json.metadata.variables):<assetId>.url,<assetId>.apiKey, etc.
Cap at 4 actions per LLM-powered node (guideline). Beyond 4, hallucination rates climb. Move actions to a downstream executor, split via router, or drop unused actions. Don't refuse a 5th if user accepts the risk.
CR-18 nuance — least privilege. Hard business constraints are enforced by router conditions, not prompts.
- Irreversible / high-stakes mutations (escalate, delete, restart, send-to-customer) MUST be in
executornodes gated byrouter. NEVER onsubagent/orchestrator— the LLM could invoke them bypassing the router. - Idempotent updates integral to the compound goal (status updates, ticket updates, log entries) MAY be on a
subagent/orchestrator. Canonical IT Help does this:crossPlatformTriage(orchestrator) hasupdate_ticketbecause updating Jira is part of the compound triage goal. It does NOT haveescalate— that's irreversible and lives on executors gated by routers.
The line: irreversible/high-stakes (executor-only, router-gated) vs idempotent/domain-natural (orchestrator OK).
LLM tier per node:
| Tier | When |
|---|---|
| Pro | Multi-step orchestration, ambiguous classification, ≥3 actions |
| Flash / mini | Single-step classification, summary, formatting, templated text |
Use default_llm for common case. Override per-node only on exceptions.
Action aliases inside reasoning.actions — short readable names (search_help, slack_update, escalate). The alias is what the LLM sees — clear aliases reduce hallucinated tool calls.
- A2A for a single API call (use MCP).
- MCP for autonomous multi-step delegation (use A2A).
- Cramming everything into one orchestrator (split or move to executors).
- Declaring fabricated
inputs:on MCP actions. - Declaring
inputs:on A2A actions (forbidden). - Forgetting
${...}variables inexchange.json.metadata.variables. - Hardcoding URLs (always parameterize).
- Using
orchestratorfor a single-action node. - Putting irreversible mutations on
subagent/orchestrator. - Mixing inline and Exchange registration for the same asset.
- Putting hard constraints in prompts (use router conditions on identifying attributes — service name + recommended action — not derived judgment flags like
requires_approval). - Modeling HITL as external
subagent → router → executor(subagents have built-in HITL). - Using
{!@...}template syntax insidea2a.*()echo helpers. - Auto-inserting missing assets during validation (ask the user to fix or remove).
The skill prefers the Anypoint CLI Agent Fabric plugin for validate/publish/deploy because it's portable (every host, including CI/CD), official MuleSoft, and stays in sync with platform changes. The MuleSoft MCP server (auto-installed in ACB/Vibes) is the fallback — same operations, host-mediated auth.
| Capability | Step | CLI command (preferred) | MCP tool (fallback) | If neither |
|---|---|---|---|---|
| Scaffold project | 0 | agent-network project create --name <n> --output-dir <d> --create-dir |
create_agent_network_project |
Write canonical scaffold directly; warn about missing groupId |
| Configure YAML | 0–5 | (skill IS the experience — edits files in place) | (skip — configure_agent_network_yaml returns a duplicate prompt template) |
— |
| Search Exchange | 1, 2 | anypoint-cli-v4 exchange asset list |
search_asset |
Ask user for groupId/assetId/version |
| Validate / build | 6 | agent-network project build |
validate_project |
Structural checklist + doc link |
| Publish to Exchange | 7 | agent-network project publish |
publish_agent_network_assets |
Doc link |
| Deploy to runtime | 8 | agent-network project deploy |
deploy_agent_network |
Doc link |
| Set up gateways | one-time | agent-network setup gateways |
(no MCP equivalent) | Doc link |
In order at each integration point:
- CLI:
command -vthe relevant binary —anypoint-cli-agent-fabric-pluginfor build/publish/deploy/setup-gatewaysanypoint-cli-v4for Exchange search and any general Anypoint operation
- MCP: Tool appears with prefix
mcp__mulesoft__(e.g.,mcp__mulesoft__search_asset). - Neither: Fall back to doc link or user prompt.
Don't probe filesystems for credentials — let CLI/host abstract auth.
As soon as a CLI command fails, fall back to the equivalent MCP tool. Do not ask the user. Do not retry the CLI. Do not stop the phase.
A CLI attempt is failed if ANY of:
command -vreturns empty.- Non-zero exit for an environment reason —
ENOENT, "command not found", plugin not installed, auth env vars unset, network error,EACCES,npm installprompt. - Hangs past timeout — ~60s for search, ~5min for build/publish/deploy.
- Succeeds but returns empty/malformed output where the schema requires content.
A CLI attempt is not failed when the failure is the user's input (invalid project name, missing field) or when the CLI legitimately reports schema errors — surface those, don't fall back.
Procedure:
- Catch the CLI failure. Note the reason silently. Do NOT narrate the failure to the user unless they ask.
- Map to the MCP equivalent (table below) and call it with the same inputs.
- If MCP is also unavailable or also fails, fall back to the no-tool path (§ "Graceful degradation").
- Tell the user only the outcome — not the tool-by-tool path.
If a CLI invocation needs more info to construct (unknown flag, unfamiliar subcommand, ambiguous syntax error): run <command> --help first; if that doesn't resolve it, do a public-web search for the CLI's documentation. Only ask the user after both fail. Don't narrate the lookup — just run the corrected command.
| Step | CLI | MCP equivalent |
|---|---|---|
| Step 1 Scaffold | anypoint-cli-agent-fabric-plugin agent-network project create |
mcp__mulesoft__create_agent_network_project |
| Phase 2 Exchange search | anypoint-cli-v4 exchange asset list |
mcp__mulesoft__search_asset |
| Step 7 Validate / build | anypoint-cli-agent-fabric-plugin agent-network project build |
mcp__mulesoft__validate_project |
| Step 8 Publish | anypoint-cli-agent-fabric-plugin agent-network project publish |
mcp__mulesoft__publish_agent_network_assets |
| Step 9 Deploy | anypoint-cli-agent-fabric-plugin agent-network project deploy |
mcp__mulesoft__deploy_agent_network |
| Step 9 Gateways setup | anypoint-cli-agent-fabric-plugin agent-network setup gateways |
(no MCP equivalent — point user at docs) |
Both CLIs share Anypoint Platform auth via the same env vars:
ANYPOINT_CLIENT_ID/ANYPOINT_CLIENT_SECRET(connected app credentials)ANYPOINT_ORG(org ID)ANYPOINT_ENV(environment name; defaults to Sandbox)ANYPOINT_HOST(defaults toanypoint.mulesoft.com; override for EU/Gov)
The general CLI also supports username/password auth via anypoint-cli-v4 conf username <u> / conf password <p> / conf organization <o>, but env-var/connected-app credentials are preferred for CI and shared sessions.
If env vars are unset and a CLI is being asked to do an auth-bearing action, point user at https://docs.mulesoft.com/anypoint-cli/latest/auth. Do not paste credentials, even temporarily.
Install:
- Agent Fabric plugin:
npm i mulesoft-anypoint-cli-agent-fabric-plugin - General CLI v4:
npm install -g anypoint-cli-v4
CLI (preferred): anypoint-cli-v4 exchange asset list --search "<query>" [--type <type>] [--organization <orgId>]
- General CLI v4 type filters:
connector|rest-api|soap-api|template|example|custom|raml-fragment. Agent-Fabric–specific types (LLM/MCP/Agent) aren't first-class here yet, so search broadly and filter the result list by name/description. - Useful follow-ups:
anypoint-cli-v4 exchange asset describe <groupId>/<assetId>/<version>to confirm details before registering. - Always pass
--organization <orgId>to scope to Private Exchange first. If no Private match, drop the flag (or pass the public org) — confirm with user before pulling Public.
MCP fallback: search_asset with assetFilters: ["llm"], ["mcp"], ["agent"].
- At least one of
searchQueryormaxResults. - Optional:
statuses,organizationId,sharedWithMe,sortCriteria,ascending,exchangeScope(Private / Public). - Always include
assetFilters— searching without narrows nothing.
If search returns no results, don't invent the asset. Tell the user: "I didn't find a matching asset in Exchange. Want to provide a custom configuration, or skip?"
CLI: anypoint-cli-agent-fabric-plugin agent-network project build --path <projectPath>. Validates configuration via Maven wrapper, generates deployable artifact. Add --debug for verbose output. Exits non-zero on validation failure.
MCP: validate_project with projectPath. Returns schema/reference/expression findings.
Two kinds of fixes:
- Auto-fix safely — formatting/indentation, missing required keys (e.g.,
info.version). - Ask the user — schema-required references missing. Never auto-insert missing assets.
Loop until clean.
CLI: anypoint-cli-agent-fabric-plugin agent-network project publish [--path <projectPath>] [--environment <env>] [--json].
assetVersionis read fromexchange.json(not a flag).--jsonreturns asset URLs in parseable form for CI.
MCP: publish_agent_network_assets with assetVersion (semver), optional projectPath, groupId.
Prereqs (both paths): authenticated; valid exchange.json (no empty default: "" for secret: true variables); assetVersion set.
After publish, surface published asset URLs.
One-time setup per private space: anypoint-cli-agent-fabric-plugin agent-network setup gateways --target-space <space>. Space defaults to agent-network-space. Skip if gateways already exist.
Gateway modes (both setup gateways and project deploy):
- Single-gateway mode (recommended):
-g/--gateway <name>. When no gateway flags are passed at all, deploy defaults to single-gateway mode usingagent-network-gw. - Separate-gateways mode:
-i/--ingress-gw <name>with-e/--egress-gw <name>.-gis mutually exclusive with-i/-e.
CLI deploy: anypoint-cli-agent-fabric-plugin agent-network project deploy [flags]. Useful flags:
--environment <name>(orANYPOINT_ENV)-g/--gateway <name>(single-gateway mode, recommended)-t/--target-space <name>(single-gateway mode: optional; separate-gateways mode: defaults toagent-network-space)--property k:v(repeatable — env-specific secrets/config; e.g.,--property openai.apiKey:STAGING_API_KEY)--dont-wait-for-agent-network(CI: return immediately)--disable-tracing(CI/test: skip telemetry)--json(parseable output)
MCP: deploy_agent_network with projectPath, environmentName, privateSpaceName, ingressGatewayName, egressGatewayName.
Prereqs (both paths): gateways exist in target space; successful publish (or assets in Exchange); secrets injected via --property or pre-filled exchange.json.
After deploy, surface URL/ID.
The skill works in Cursor, standalone Claude Code, Codex — anywhere without MuleSoft tooling. When neither CLI nor MCP is available:
- Phase 1/2 — search: Ask the user directly. For Exchange-mode assets, get
groupId/assetId/versionand (for MCPs) transport kind + tool names. For unknown assets, register an inline placeholder per Case C. Tell the user: "To search Exchange directly, installanypoint-cli-v4(npm i -g anypoint-cli-v4)." - Step 7 — validation: Run the structural checklist. Tell the user: "To run MuleSoft's full schema validator, install the CLI plugin (
npm i mulesoft-anypoint-cli-agent-fabric-plugin) or use the MuleSoft MCP server in your IDE. CI/CD reference: https://docs.mulesoft.com/anypoint-code-builder/af-build-agent-networks-in-a-ci-cd-environment." - Step 8 — publish: Point at https://docs.mulesoft.com/anypoint-code-builder/af-publish-agent-network-assets.
- Step 9 — deploy: Point at https://docs.mulesoft.com/anypoint-code-builder/af-deploy-agent-network-targets.
CLI: anypoint-cli-agent-fabric-plugin agent-network project create --name <project-name> --output-dir <parent-dir> --create-dir. Key flags:
-n, --name=<value>(required) — project name; becomes defaultassetId(lowercased, hyphenated).-o, --output-dir=<value>— parent directory for the new project (default: current dir).--create-dir— create a new directory atoutput-dirnamed after the project (recommended; without it, files land directly inoutput-dir).--asset-id,--asset-version(default0.0.0),--api-version(defaultv1) — override the defaults written intoexchange.json.--organization=<orgId>/--environment=<name>— pulled fromANYPOINT_ORG/ANYPOINT_ENVenv vars by default.
The CLI writes a starter agent-network.yaml (with agentNetwork: 2.0.0), exchange.json (with the correct groupId/organizationId/classifier: agentic-network), and an empty brokers/ directory. The skill then edits these in place.
MCP fallback: create_agent_network_project — same inputs as the CLI.
No-tool fallback: write the canonical scaffold (per canonical-example.md) directly. Tell the user to fill in groupId/organizationId in exchange.json before publish.
- Don't call
configure_agent_network_yaml— it returns a duplicate prompt template that overlaps with the skill's guided experience. - Don't silently shell out for auth-bearing actions without confirming env vars are set; never paste credentials inline.
- Don't auto-deploy. Step 7 ends at "validated"; 8 is publish; 9 is deploy. Both opt-in.
- Don't auto-insert missing assets when validation reports a dangling reference. Ask user.
- Don't fabricate MCP
tool_name, asset IDs, or model IDs even when neither CLI nor MCP is present.