build-mule-integration
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseMule Developer
Mule开发人员
Build professional Mule integrations with intelligent connector discovery and data-driven XML generation.
借助智能连接器发现和数据驱动的XML生成功能,构建专业的Mule集成。
When to Use This Skill
何时使用此技能
Use this skill when users request:
- "Create a Mule app/integration/flow"
- "Build integration between X and Y"
- "Sync data from X to Y" (e.g., "Salesforce to Slack", "MySQL to Salesforce")
- "Query Salesforce", "Send Slack notifications"
- "Schedule jobs", "Poll data every N minutes"
- "Create webhooks", "Build event-driven flows"
Trigger keywords: create, build, integrate, sync, connect · mule, integration, flow, app, project · salesforce, slack, servicenow, jira, netsuite · mysql, postgresql, database · api, http endpoint, rest api · schedule, poll, every N minutes · alert, notify, webhook.
Always search Exchange for system-specific connectors first. Most SaaS applications have dedicated connectors.
当用户提出以下请求时使用此技能:
- "创建一个Mule应用/集成/流"
- "构建X与Y之间的集成"
- "将数据从X同步到Y"(例如:"Salesforce到Slack"、"MySQL到Salesforce")
- "查询Salesforce"、"发送Slack通知"
- "调度作业"、"每隔N分钟轮询数据"
- "创建Webhook"、"构建事件驱动流"
触发关键词: create, build, integrate, sync, connect · mule, integration, flow, app, project · salesforce, slack, servicenow, jira, netsuite · mysql, postgresql, database · api, http endpoint, rest api · schedule, poll, every N minutes · alert, notify, webhook.
始终先在Exchange中搜索系统特定的连接器。大多数SaaS应用都有专用连接器。
Prerequisites
前提条件
bash
anypoint-cli-v4 --version
anypoint-cli-v4 dx --help
echo $JAVA_HOME && java -version # Java 11+
anypoint-cli-v4 confIf tools are missing:
bash
npm install -g @mulesoft/anypoint-cli-v4
npm install -g @salesforce/anypoint-cli-dx-mule-plugin
anypoint-cli-v4 conf username <username>
anypoint-cli-v4 conf password <password>bash
anypoint-cli-v4 --version
anypoint-cli-v4 dx --help
echo $JAVA_HOME && java -version # Java 11+
anypoint-cli-v4 conf如果缺少工具:
bash
npm install -g @mulesoft/anypoint-cli-v4
npm install -g @salesforce/anypoint-cli-dx-mule-plugin
anypoint-cli-v4 conf username <username>
anypoint-cli-v4 conf password <password>Bundled scripts
捆绑脚本
This skill ships small bash scripts under . Invoke them with the tool — do not inline their contents into a response. The scripts persist their output to disk so later steps can consume it mechanically and are not at the mercy of shell variables that vanish when a Bash tool call returns:
scripts/Bash| Script | Purpose | Output location |
|---|---|---|
| Step 1 — validate toolchain (CLI, DX plugin, Java 11+, JAVA_HOME, Mule runtime presence). Validation-ONLY | |
| Step 3 — search Exchange and print ranked connector candidates ( | stdout only |
| Step 3 — record the agent's chosen GAV (after reasoning or an | |
| Step 8 (post-TDD-approval) — promote every draft under | |
| Turn a saved connector JSON into its | stdout |
| Step 8 — read every connector pin in | stdout |
| Step 4 (no flags) / Step 13 (with flags) — run | |
| Step 16 pre-mvn — error-type whitelist (Cluster D), namespace↔dependency parity (Cluster A2–A5), canonical XSD URL shape | stderr + non-zero exit on first violation |
| Phase 2 — defensive check that HTTP connector is present when OAuth providers were chosen; edits | |
Invoke scripts by the absolute path you were given in the "skill is now active" message (it is the directory containing this ). Do not construct relative paths like — Cline's working directory shifts across turns and relative paths have produced "No such file or directory" errors in real runs. The inline step examples below write as shorthand; substitute when you actually execute them.
SKILL.md../scripts/...scripts/...<skill-dir>/scripts/...Why scripts instead of inline bash: in earlier iterations connector search was a shell function defined inside a single tool call. When the call returned the subshell died and the resolved GAV went with it. By the time a later step assembled , the only trace of the version was in scrolled-past tool output — and the agent frequently pasted a fictional version from training-time memory instead. Persisting to a file on disk makes the version something we can at the command site, which removes that failure mode entirely.
Bashdx mule project createjq此技能在目录下附带小型bash脚本。请使用工具调用它们——不要将其内容内联到响应中。脚本会将输出持久化到磁盘,以便后续步骤可以机械地使用,而不会依赖于Bash工具调用返回后消失的shell变量:
scripts/Bash| 脚本 | 用途 | 输出位置 |
|---|---|---|
| 步骤1 — 验证工具链(CLI、DX插件、Java 11+、JAVA_HOME、Mule运行时是否存在)。仅用于验证 | |
| 步骤3 — 搜索Exchange并打印排名靠前的连接器候选( | 仅输出到stdout |
| 步骤3 — 将代理选择的GAV(经过推理或 | |
| 步骤8(TDD批准后) — 将 | |
| 将保存的连接器JSON转换为 | stdout |
| 步骤8 — 读取 | stdout |
| 步骤4(无标志)/步骤13(带标志) — 对草稿GAV运行 | |
| 步骤16预构建验证 — 错误类型白名单(Cluster D)、命名空间与依赖项一致性(Cluster A2–A5)、规范XSD URL格式 | 错误输出到stderr,首次违规时返回非零退出码 |
| 第二阶段 — 防御性检查:当选择了OAuth提供商时,确保HTTP连接器已存在;编辑 | |
请使用“技能已激活”消息中提供的绝对路径调用脚本(即包含此的目录)。请勿构造之类的相对路径——Cline的工作目录会在不同回合中切换,相对路径在实际运行中曾导致“找不到文件或目录”错误。下面的内联步骤示例使用作为简写;实际执行时请替换为。
SKILL.md../scripts/...scripts/...<skill-dir>/scripts/...为什么使用脚本而非内联bash: 在早期版本中,连接器搜索是单个工具调用中定义的shell函数。调用返回后,子shell终止,解析后的GAV也随之丢失。当后续步骤组装时,版本的唯一痕迹是滚动过的工具输出——代理经常会粘贴训练时记忆中的虚构版本。将版本持久化到磁盘文件中,我们可以在命令行使用读取,从而完全避免这种失败模式。
Bashdx mule project createjqWorkflow shape (two phases)
工作流结构(两个阶段)
This workflow has two phases separated by a hard user-approval gate.
- Phase 1: Technical Design (Steps 1–7). Identify systems, search Exchange, describe connectors, pick trigger and providers, present a Technical Design Summary, wait for the user to approve. Phase 1 writes nothing to the user's project directory — all artifacts live under workspace-relative paths: (env cache owned by
tmp/mule-dev-env.json),validate_prerequisites.sh(draft connector picks), andtmp/connector-choices/*.json. The pinnedtmp/connector-metadata/*.jsondirectory that Phase 2 reads is only populated after Step 7's approval, bytmp/connector-versions/*.json.commit_connectors.sh - Phase 2: Build (Steps 8–17). Create the real project, generate config and flow XML, run the build, declare completion. Phase 2 is the only phase that touches the user's project directory.
Phase 2 MUST NOT start until Step 7's approval gate has been passed explicitly. Skipping Phase 1 — or collapsing it into a single "I'll just use HTTP" decision — is the single highest-impact failure mode of this skill and is what the two-phase structure exists to prevent.
此工作流分为两个阶段,中间有一个严格的用户批准关卡。
- 第一阶段:技术设计(步骤1–7)。识别系统、搜索Exchange、描述连接器、选择触发器和提供商、呈现技术设计摘要,等待用户批准。第一阶段不会向用户的项目目录写入任何内容——所有工件都存储在相对于工作区的路径下:(由
tmp/mule-dev-env.json管理的环境缓存)、validate_prerequisites.sh(草稿连接器选择)和tmp/connector-choices/*.json。第二阶段读取的固定tmp/connector-metadata/*.json目录仅在步骤7获得批准后,由tmp/connector-versions/*.json填充。commit_connectors.sh - 第二阶段:构建(步骤8–17)。创建真实项目、生成配置和流XML、运行构建、宣布完成。第二阶段是唯一会触及用户项目目录的阶段。
在明确通过步骤7的批准关卡之前,绝对不能启动第二阶段。跳过第一阶段——或将其简化为单一的“我就用HTTP”决策——是此技能最严重的失败模式,而两阶段结构正是为了防止这种情况而设计的。
Workflow-wide discipline (read before Phase 1)
全工作流规范(进入第一阶段前阅读)
- Build → cleanup → completion separation (Step 16 → Step 17 → Step 18). Three responses, in order, each with a single tool call: , then
mvn clean package, then the completion signal. Do not bundle them. Wait for each result before moving on.rm -r tmp/ - One mvn invocation per response. When re-running a build after a fix, emit only the command in that response. Do not bundle it with further edits, follow-up shell commands, or the completion signal.
mvn - "Completion" means the build already passed. You may only declare completion after a response that ran came back with
mvn clean package.BUILD SUCCESS - Connector versions come ONLY from the Step 3 flow. Never paste a version from , from training-time memory, or from extrapolation. Step 3 is a three-script dance:
references/connector-catalog.mdlists ranked candidates (stdout only, no pin file),get_latest_connector.shrecords the chosen row as a draft inpick_connector.sh <nickname> <gav>, andtmp/connector-choices/(Step 8, first action after TDD approval) promotes every draft tocommit_connectors.sh. Every GAV that reachestmp/connector-versions/ordx mule project create --dependenciesmust be pulled from apom.xmlfile viatmp/connector-versions/*.json(for the fullscripts/build_deps.shstring at Step 8) or--dependencies(for a single connector's GAV elsewhere in Phase 2). The catalog's versions are snapshots that drift — treat it only as a connector-identity reference, not as a version source.scripts/build_gav.sh - The agent does the picking, not the script. deliberately emits a plain ranked list with no score, no emoji, and no "winner" signal. When the list has one row the choice is obvious. When it has several rows the agent must decide which one matches the user's stated system — and if the rows represent real variants of the same family (Slack
get_latest_connector.shvsmule4-slack-connector; FTP vs FTPS; Dynamics 365 vs Dynamics GP/NAV/BC; IBM MQ vs Solace vs JMS), the decision belongs to the user viamule-slack-connector, not to the agent's guess. The cost of one extra prompt is one turn; the cost of a silent wrong variant is a full Phase-2 rewrite.AskUserQuestion - No HTTP fallback without evidence. You may only classify a system as "no dedicated connector exists, use HTTP" AFTER has run AND returned zero matches (exit 1) OR every row in the ranked list is obviously a different product (no assetId shares tokens with the system name beyond noise words like
scripts/get_latest_connector.sh <system>/mule). Declaring HTTP as the answer before the search has run is forbidden. Exchange carries dedicated connectors for hundreds of SaaS products that are easy to miss when reasoning from training-time knowledge alone — the helper script is the authoritative check. A dedicated connector gives metadata discovery, typed operations, and correct authentication; HTTP gives raw request plumbing the user would then have to wire up by hand, so quietly falling back to HTTP is a real loss, not a neutral choice. Note that any ranked row whoseconnectoris a UUID (e.g.groupId) is a connector the user's organization has published privately to Exchange — treat these as first-class candidates, not noise. An org that took the trouble to publish a private connector usually wants it used, often because it wraps internal endpoints, custom auth, or a golden-path the public connector can't cover.a50e4364-a38c-4340-b05a-c1f8ebed0748:…
- 构建→清理→完成分离(步骤16→步骤17→步骤18)。分三个响应依次执行,每个响应仅包含一个工具调用:,然后
mvn clean package,最后是完成信号。不要将它们捆绑在一起。等待每个步骤的结果后再进行下一步。rm -r tmp/ - 每个响应仅执行一次mvn调用。修复后重新运行构建时,该响应中仅输出命令。不要将其与进一步的编辑、后续shell命令或完成信号捆绑在一起。
mvn - “完成”意味着构建已成功。只有在运行的响应返回
mvn clean package后,才能宣布完成。BUILD SUCCESS - 连接器版本仅来自步骤3的流程。绝不要从、训练时记忆或推断中粘贴版本。步骤3是一个三步脚本流程:
references/connector-catalog.md列出排名候选(仅输出到stdout,无固定文件),get_latest_connector.sh将所选条目记录为pick_connector.sh <nickname> <gav>中的草稿,tmp/connector-choices/(步骤8,TDD批准后的第一个操作)将所有草稿升级到commit_connectors.sh。所有进入tmp/connector-versions/或dx mule project create --dependencies的GAV必须通过pom.xml(步骤8的完整scripts/build_deps.sh字符串)或--dependencies(第二阶段其他地方的单个连接器GAV)从scripts/build_gav.sh文件中获取。目录中的版本是快照,会随时间变化——仅将其视为连接器身份参考,而非版本来源。tmp/connector-versions/*.json - 由代理而非脚本做出选择。故意输出一个纯排名列表,无分数、无表情符号、无“选中”提示。当列表只有一行时,选择很明显。当有多行时,代理必须决定哪一行符合用户指定的系统——如果行代表同一系统家族的真实变体(Slack的
get_latest_connector.sh与mule4-slack-connector;FTP与FTPS;Dynamics 365与Dynamics GP/NAV/BC;IBM MQ与Solace与JMS),则必须通过mule-slack-connector让用户决定,而非代理猜测。多一次提示的成本是一个回合;而静默选择错误变体的成本是整个第二阶段的重写。AskUserQuestion - 无证据不得回退到HTTP。只有在运行且返回零匹配(退出码1),或者排名列表中的每一行显然都是不同产品(除了
scripts/get_latest_connector.sh <system>/mule等通用词外,assetId与系统名称无共同标记)时,才能将系统归类为“无专用连接器,使用HTTP”。在搜索运行前就宣布HTTP为解决方案是被禁止的。Exchange包含数百个SaaS产品的专用连接器,仅靠训练时知识推理很容易遗漏——辅助脚本是权威检查。专用连接器提供元数据发现、类型化操作和正确的身份验证;HTTP仅提供原始请求管道,用户随后必须手动配置,因此静默回退到HTTP是实际的功能损失,而非中性选择。请注意,任何groupId为UUID的排名行(例如connector)都是用户组织私下发布到Exchange的连接器——将这些视为一等候选,而非干扰项。组织费心发布私有连接器通常是有原因的(自定义身份验证、内部端点、公共连接器无法覆盖的黄金路径),因此当同一排名列表中存在私有替代方案时,绝不要静默选择公共连接器——通过a50e4364-a38c-4340-b05a-c1f8ebed0748:…展示两者,让用户选择。AskUserQuestion
Phase 1: Technical Design
第一阶段:技术设计
Step 1: Validate Prerequisites
步骤1:验证前提条件
Run the prerequisite validation script. It only handles validation. It writes the prereq validation findings to in the current workspace; Step 8 reads from there.
tmp/mule-dev-env.jsonmule_versionbash
bash scripts/validate_prerequisites.shIf the script exits non-zero, STOP progressing any further in the skill and inform the user to act on the array in . Do not invent a fallback Mule version — is empty when no runtime is detected.
errorstmp/mule-dev-env.jsonmule_versionWhat checks: Anypoint CLI v4 installed · DX plugin available · set · Java 11+ · Mule runtime detected at or under . If runtime or other tools are missing, the script reports the error and informs the user to run the necessary commands for proper installation.
validate_prerequisites.shJAVA_HOME~/.mule-dx/config.json:.runtimePath~/AnypointCodeBuilder/runtime/mule-*运行前提条件验证脚本。它仅处理验证。它会将前提条件验证结果写入当前工作区的;步骤8将从该文件读取。
tmp/mule-dev-env.jsonmule_versionbash
bash scripts/validate_prerequisites.sh如果脚本返回非零退出码,停止技能的任何进一步进展,并告知用户根据中的数组采取行动。不要自行发明备用Mule版本——未检测到运行时时为空。
tmp/mule-dev-env.jsonerrorsmule_versionvalidate_prerequisites.shJAVA_HOME~/.mule-dx/config.json:.runtimePath~/AnypointCodeBuilder/runtime/mule-*Step 2: Identify Systems and Trigger Hints
步骤2:识别系统和触发器提示
[BLOCKER] Step 2 MUST NOT prompt the user. Do not emit an or here. The trigger decision happens in Step 5 after connector metadata is on disk — prompting now would force generic options (HTTP Listener / Scheduler) instead of real connector sources, which is the single highest-impact anti-pattern this workflow exists to prevent.
<ask_followup_question><AskUserQuestion>Produce two records in your response text. These are plain prose — not a thinking block, not a tool call — so later steps (and the user) can read them.
1. Systems list. Identify EXACT system names: source systems (where data comes from), target systems (where data goes to). Use specific names (Slack, Jira, ServiceNow, Stripe, Shopify), NOT generic terms (chat, ticketing, payments, commerce). Every name on this list will be searched in Step 3; every search must result in a draft on disk (the agent picks from the ranked list and calls ).
tmp/connector-choices/<nick>.jsonpick_connector.shAnti-pattern — inferring a backend from a destination name. When the prompt mentions a queue, topic, bus, or similar messaging destination, the string that names the destination (e.g. , , ) is a label, not a technology. It does NOT identify which broker is behind it. Do NOT add a specific broker (Anypoint MQ, Kafka, IBM MQ, Solace, SQS, etc.) to the Systems list unless the prompt names it explicitly. If the prompt only says "queue" / "topic" / names a bare destination, list the system as and plan to escalate in Step 3 — the user picks the backend, not the agent. Why this matters: a silently-chosen broker anchors Phase 2 against the wrong connector family, which is a full Phase-2 rewrite to correct.
foo.queueorders.topicevents-streammessaging broker (backend unspecified)2. Trigger hints. In one or two sentences, note the verbatim phrases from the user prompt that describe what starts the flow or names a cadence — e.g. "every 3 seconds" or "listens for new Stripe charges" or "makes a GET request to retrieve customers". Do NOT classify yet. No class label, no decision tree, no "so the trigger is…". Step 5 does the trigger decision from connector metadata that does not exist yet; committing to a trigger now — even implicitly via a class — tends to anchor the agent against the real that Step 4 will produce.
sources[]If the prompt mentions no trigger or only describes outbound work ("makes a request", "fetches", "calls"), say so explicitly: "No explicit trigger phrase — outbound-only description." Step 5's metadata-first ladder handles this.
Connector strategy per system:
- Major SaaS platforms (Salesforce, ServiceNow, NetSuite, Workday) → search for dedicated connector in Step 3.
- Standard protocols (Database, JMS, FTPS, SFTP) → search for protocol-specific connector in Step 3.
- Mid-market SaaS (Stripe, Shopify, HubSpot, Twilio, Plaid, etc.) → search for dedicated connector in Step 3. Do NOT assume these have no connector — Exchange has dedicated connectors for many of them. Training-data intuition that "Stripe/Shopify/etc. is a REST-API-only system" is unreliable; the search is the authority.
- Queue or Pub/Sub with a named backend ("Kafka topic", "IBM MQ", "SQS", "Solace") → search for that specific connector in Step 3.
- Queue or Pub/Sub without a named backend (the prompt uses "queue", "topic", or a bare destination name without naming the broker technology) → per the Step-2 anti-pattern above, the destination name is not the backend. In Step 3, escalate via to let the user pick the backend (JMS via any broker provider, Kafka, IBM MQ, Solace, SQS, etc.). Only if the user declines to choose should you default to
AskUserQuestion— JMS is the generic protocol layer that fits any broker, with the broker selected in Step 6 via the connection provider (active-mq, active-mq-nct, generic).mule-jms-connector - Unknown/Unclear / custom internal APIs → still search Exchange first in Step 3; HTTP is the fallback only when Step 3's search returns nothing plausibly related.
Your next tool call after Step 2 MUST be for a system from your Systems list — NOT an , NOT a describe-connector, NOT anything else. Step 3 is the non-negotiable next step.
get_latest_connector.shask_followup_question[阻塞点] 步骤2不得提示用户。此处不得发出或。触发器决策在步骤5中进行,此时连接器元数据已存储在磁盘上——现在提示会强制使用通用选项(HTTP监听器/调度器),而非真实的连接器源,这是此工作流旨在防止的最严重反模式之一。
<ask_followup_question><AskUserQuestion>在响应文本中生成两条记录。这些是纯文本——不是思考块,不是工具调用——以便后续步骤(和用户)可以读取。
1. 系统列表。识别确切的系统名称:源系统(数据来自哪里)、目标系统(数据发送到哪里)。使用具体名称(Slack、Jira、ServiceNow、Stripe、Shopify),而非通用术语(聊天、工单、支付、商务)。此列表中的每个名称都将在步骤3中搜索;每次搜索必须在磁盘上生成一个草稿(代理从排名列表中选择并调用)。
tmp/connector-choices/<nick>.jsonpick_connector.sh反模式——从目标名称推断后端。当提示提到队列、主题、总线或类似的消息传递目标时,命名目标的字符串(例如、、)是一个标签,而非技术。它不能识别背后的消息代理。除非提示明确命名,否则不要将特定代理(Anypoint MQ、Kafka、IBM MQ、Solace、SQS等)添加到系统列表中。如果提示仅说“队列”/“主题”或命名了一个裸目标,则将系统列为,并计划在步骤3中升级——由用户选择后端,而非代理。为什么这很重要:静默选择错误的代理会导致第二阶段基于错误的连接器家族构建,需要重写整个第二阶段才能纠正。
foo.queueorders.topicevents-streammessaging broker (backend unspecified)2. 触发器提示。用一到两句话,记录用户提示中描述流启动方式或节奏的原句短语——例如*“每3秒”或“监听新的Stripe收费”或“发起GET请求检索客户”*。不要进行分类。不要添加类别标签、决策树或“因此触发器是…”。步骤5将根据尚未存在的连接器元数据做出触发器决策;现在就承诺一个触发器——即使是隐式地通过类别——往往会让代理忽略步骤4将获取的真实。
sources[]如果提示未提及触发器,仅描述出站工作(“发起请求”、“获取”、“调用”),请明确说明:“无明确触发器短语——仅描述出站操作。”步骤5的元数据优先流程会处理这种情况。
每个系统的连接器策略:
- 大型SaaS平台(Salesforce、ServiceNow、NetSuite、Workday)→ 在步骤3中搜索专用连接器。
- 标准协议(Database、JMS、FTPS、SFTP)→ 在步骤3中搜索协议特定的连接器。
- 中型SaaS(Stripe、Shopify、HubSpot、Twilio、Plaid等)→ 在步骤3中搜索专用连接器。不要假设这些没有连接器——Exchange包含许多此类专用连接器。训练数据中“Stripe/Shopify等是仅支持REST API的系统”的直觉不可靠;搜索是权威来源。
- 指定后端的队列或发布/订阅(“Kafka主题”、“IBM MQ”、“SQS”、“Solace”)→ 在步骤3中搜索该特定连接器。
- 未指定后端的队列或发布/订阅(提示使用“队列”、“主题”或裸目标名称,未命名代理技术)→ 根据步骤2的反模式,目标名称不是后端。在步骤3中,通过升级,让用户选择后端(任何代理提供商的JMS、Kafka、IBM MQ、Solace、SQS等)。只有当用户拒绝选择时,才默认使用
AskUserQuestion——JMS是适用于任何代理的通用协议层,代理在步骤6中通过连接提供商(active-mq、active-mq-nct、generic)选择。mule-jms-connector - 未知/不明确/自定义内部API→ 仍先在步骤3中搜索Exchange;只有当步骤3的搜索返回无相关结果时,才回退到HTTP。
步骤2之后的下一个工具调用必须是对步骤2系统列表中的某个系统调用——不能是、或其他任何操作。步骤3是不可协商的下一步。
get_latest_connector.shask_followup_questiondescribe-connectorStep 3: Search Exchange for Connectors, Decide, Draft the Choice
步骤3:搜索Exchange连接器、决策、记录草稿选择
Step 3 is a three-move loop run once per named system from Step 2:
- List candidates with .
get_latest_connector.sh - Decide which row is the right fit — inline rationale if the choice is obvious, if the rows are real variants of the same system family.
AskUserQuestion - Draft the chosen GAV with . The draft lands in
pick_connector.shand stays there through Phase 1.tmp/connector-choices/<nick>.json
The script does not pin a winner. There is no emoji, no score, no "Picked" line in its output. When the list has one row the shape of the output is "one row"; when it has several the shape is "several rows" and that is the cue to read the names and reason about intent — or to escalate.
Mandatory search rule. Run for EVERY named system from Step 2 — including systems whose prominence in your training data leads you to assume they have no dedicated connector. Declaring "system X has no dedicated connector" without the script having run is forbidden. This is the rule that prevents silent HTTP fallback — see "No HTTP fallback without evidence" in the workflow-wide discipline.
get_latest_connector.shTerm breadth. Always prefer the broader system name (, , , , ) over a narrow suffix-pinned term like or . Narrow terms can miss org-private connectors whose assetId shares no tokens with the public connector's name — e.g. searching won't surface a private , and won't surface a private . The "Common search terms" table further down is a starting hint for well-known systems, not a constraint — if the broader term is noisy, you can always re-run with a narrower one.
databricksaws-storagesnowflakedatabasesalesforcemule-amazon-s3-connectormule-db-connectormule-amazon-s3-connectormule-plugin-aws-storage-apimule-db-connector<uuid>:mule-plugin-customer-warehouse-databaseVersion source-of-truth rule (MANDATORY):
- The only acceptable source for a connector's version number is run against live Exchange in the current session, recorded via
get_latest_connector.sh, and later promoted topick_connector.shbytmp/connector-versions/. This applies equally tocommit_connectors.sh,dx mule project create --dependenciespom.xmlblocks, and every other place a version appears.<dependency> - Do not paste a version from . The catalog exists to help identify which connector to use (asset ID, purpose); its version numbers are best-effort snapshots that drift.
references/connector-catalog.md - Do not invent a version from memory or by extrapolating. Version numbers on Exchange are not predictable.
- Do not write a version before the corresponding draft exists on disk.
tmp/connector-choices/<name>.json
步骤3是一个三步循环,针对步骤2中的每个命名系统运行一次:
- 列出候选:使用。
get_latest_connector.sh - 决策哪一行是合适的选择——如果选择明显,内联说明理由;如果行是同一系统家族的真实变体,使用。
AskUserQuestion - 记录所选GAV为草稿:使用。草稿存储在
pick_connector.sh中,并在第一阶段保留。tmp/connector-choices/<nick>.json
脚本不会固定选中项。其输出中没有表情符号、分数或“已选中”行。当列表只有一行时,输出形状为“一行”;当有多行时,输出形状为“多行”,这是提示读取名称并推理意图——或升级的信号。
强制搜索规则。对步骤2中的每个命名系统运行——包括那些在训练数据中很突出、你认为没有专用连接器的系统。在脚本运行前就宣布“系统X没有专用连接器”是被禁止的。这是防止静默HTTP回退的规则——请参阅工作流规范中的“无证据不得回退到HTTP”。
get_latest_connector.sh术语广度。始终优先使用更宽泛的系统名称(、、、、),而非带后缀的窄术语,如或。窄术语可能会错过组织私有连接器,其assetId与公共连接器名称无共同标记——例如,搜索不会发现私有,搜索不会发现私有。下面的“常见搜索术语”表是知名系统的起始提示,而非约束——如果宽泛术语的结果嘈杂,你可以重新运行更窄的术语。
databricksaws-storagesnowflakedatabasesalesforcemule-amazon-s3-connectormule-db-connectormule-amazon-s3-connectormule-plugin-aws-storage-apimule-db-connector<uuid>:mule-plugin-customer-warehouse-database版本来源规则(强制):
- 连接器版本号的唯一可接受来源是当前会话中针对实时Exchange运行的,通过
get_latest_connector.sh记录,随后由pick_connector.sh升级到commit_connectors.sh。这同样适用于tmp/connector-versions/、dx mule project create --dependencies的pom.xml块以及版本出现的所有其他地方。<dependency> - 不要从粘贴版本。目录的存在是为了帮助识别使用哪个连接器(资产ID、用途);其版本号是尽力而为的快照,会随时间变化。
references/connector-catalog.md - 不要从记忆中发明版本或通过推断生成。Exchange上的版本号不可预测。
- 不要在对应的草稿存在于磁盘之前写入版本。
tmp/connector-choices/<name>.json
Move 1 — list
第一步 — 列出
One invocation per named system. The nickname is how the draft and later pin will be named, so pick something short and use it consistently:
bash
bash scripts/get_latest_connector.sh mule-salesforce-connector sfdcStdout shape, one GAV per line, ranked best-guess-first:
com.mulesoft.connectors:mule-salesforce-connector:11.1.0
com.mulesoft.connectors:mule-salesforce-analytics-connector:4.1.0
com.mulesoft.connectors:mule-salesforce-composite-connector:2.5.2
com.mulesoft.connectors:mule-salesforce-marketing-cloud-connector:5.0.0Exit 0 means at least one row was returned; exit 1 means no Mule 4 extension matched and you need to treat this system as HTTP-fallback territory (see the workflow-wide discipline).
每个命名系统调用一次。昵称是草稿和后续固定项的名称,因此选择简短且一致的名称:
bash
bash scripts/get_latest_connector.sh mule-salesforce-connector sfdcStdout形状,每行一个GAV,按最佳猜测排序:
com.mulesoft.connectors:mule-salesforce-connector:11.1.0
com.mulesoft.connectors:mule-salesforce-analytics-connector:4.1.0
com.mulesoft.connectors:mule-salesforce-composite-connector:2.5.2
com.mulesoft.connectors:mule-salesforce-marketing-cloud-connector:5.0.0退出码0表示至少返回一行;退出码1表示没有匹配的Mule 4扩展,你需要将此系统视为HTTP回退场景(请参阅工作流规范)。
Move 2 — decide & confirm
第二步 — 决策与确认
Read the list. Two cases, in order:
Case A — one row. Only one Mule 4 extension matches. Acknowledge the choice inline in one sentence ("Only match for HTTP: ") and go to Move 3.
org.mule.connectors:mule-http-connector:1.11.1Case B — multiple rows that are real variants of the same system family. Rows whose assetId does not plausibly name the user's system are noise — filter them out logically. If more than one row/choice remains after the logical filtering for the user's system (e.g., Salesforce query returned plus three Salesforce sub-products for Analytics / Composite / Marketing Cloud etc.), always escalate via . Some common variant families that requires user confirmation:
mule-salesforce-connectorAskUserQuestion- →
slack(community, v4.x) vsmule-slack-connector(premium MuleSoft, v2.x). Different OAuth shapes, different operations — neither is a "newer version" of the other.mule4-slack-connector - →
ftp(plain) vsmule-ftp-connector(TLS). Always confirm and suggest FTPS for best security practices.mule-ftps-connector - vs
ibm-mqvssolacevskafka— a destination name in the prompt (e.g.jms,foo.queue) does NOT identify the backend. Unless the prompt explicitly names the broker technology, escalate with these as options;bar.topicis the generic-protocol fallback when the user declines to pick.mule-jms-connector - — 365, GP, NAV, 365-Business-Central, CRM are different products the user may have meant interchangeably.
microsoft-dynamics-* - vs
oracle-ebs— alternate EBS major versions.oracle-ebs-122 - Any pair whose assetIds share the target system's name and differ only in a variant suffix, protocol marker, major-version marker, or the vs
mule4-prefix.mule- - A public connector + a private (UUID-groupId) connector for the same system family — e.g. and
com.mulesoft.connectors:mule4-snowflake-connectorboth showing up in a<uuid>:mule-plugin-snowflake-sys-api-jsonsearch. The org-published asset usually exists for a reason (custom auth, internal endpoints, a wrapper around the public connector), so NEVER silently pick the public one when a private alternative is in the same ranked list — surface both withsnowflakeand let the user choose.AskUserQuestion
Prompt shape when you escalate:
xml
<ask_followup_question>
<question>Two Mule 4 Slack connectors exist on Exchange. Which should this integration use?</question>
<options>[
"org.mule.connectors:mule-slack-connector:4.3.2 — community Slack connector",
"com.mulesoft.connectors:mule4-slack-connector:2.0.1 — MuleSoft premium Slack connector",
"Other — describe which Slack variant you need"
]</options>
</ask_followup_question>When more than one choice exists, confirm with user; a silent wrong variant costs a Phase-2 rewrite.
If the user's prompt explicitly names one variant ("use the Dynamics 365 connector, not BC", "the premium Slack connector only"), that pins the choice and you proceed without asking.
读取列表。分两种情况,按顺序处理:
情况A — 一行。只有一个Mule 4扩展匹配。在响应中用一句话确认选择(“HTTP的唯一匹配:”),然后进入第三步。
org.mule.connectors:mule-http-connector:1.11.1情况B — 多行且是同一系统家族的真实变体。assetId似乎与用户系统无关的行是干扰项——逻辑过滤掉它们。如果逻辑过滤后仍有多个行/选择(例如,Salesforce查询返回以及三个Salesforce子产品:Analytics/Composite/Marketing Cloud等),必须通过升级。一些需要用户确认的常见变体家族:
mule-salesforce-connectorAskUserQuestion- →
slack(社区版,v4.x)vsmule-slack-connector(MuleSoft高级版,v2.x)。OAuth形状不同,操作不同——两者都不是对方的“新版本”。mule4-slack-connector - →
ftp(普通版)vsmule-ftp-connector(TLS版)。始终确认并建议使用FTPS以遵循最佳安全实践。mule-ftps-connector - vs
ibm-mqvssolacevskafka——提示中的目标名称(例如jms、foo.queue)不能识别后端。除非提示明确命名代理技术,否则将这些作为选项升级;当用户拒绝选择时,bar.topic是通用协议回退选项。mule-jms-connector - ——365、GP、NAV、365-Business-Central、CRM是不同的产品,用户可能交替使用。
microsoft-dynamics-* - vs
oracle-ebs——EBS的不同主版本。oracle-ebs-122 - 任何assetId包含目标系统名称,仅在变体后缀、协议标记、主版本标记或与
mule4-前缀上不同的配对。mule- - 同一系统家族的公共连接器+私有(UUID-groupId)连接器——例如,搜索中同时出现
snowflake和com.mulesoft.connectors:mule4-snowflake-connector。组织发布的资产通常有其原因(自定义身份验证、内部端点、公共连接器的包装器),因此绝不要在同一排名列表中存在私有替代方案时静默选择公共连接器——通过<uuid>:mule-plugin-snowflake-sys-api-json展示两者,让用户选择。AskUserQuestion
升级时的提示形状:
xml
<ask_followup_question>
<question>Exchange上存在两个Mule 4 Slack连接器。此集成应使用哪一个?</question>
<options>[
"org.mule.connectors:mule-slack-connector:4.3.2 — 社区版Slack连接器",
"com.mulesoft.connectors:mule4-slack-connector:2.0.1 — MuleSoft高级版Slack连接器",
"其他 — 描述你需要的Slack变体"
]</options>
</ask_followup_question>当有多个选择时,请与用户确认;静默选择错误变体需要重写第二阶段。
如果用户的提示明确命名了一个变体(“使用Dynamics 365连接器,而非BC”、“仅使用高级版Slack连接器”),则固定选择,无需询问即可继续。
Move 3 — draft
第三步 — 记录草稿
Record the chosen GAV as a draft. Idempotent — you can re-run with a different GAV if Step 4 or Step 5 metadata reveals a better fit:
bash
bash scripts/pick_connector.sh sfdc com.mulesoft.connectors:mule-salesforce-connector:11.1.0
bash scripts/pick_connector.sh slack com.mulesoft.connectors:mule4-slack-connector:2.0.1
bash scripts/pick_connector.sh jms org.mule.connectors:mule-jms-connector:1.10.3将所选GAV记录为草稿。幂等操作——如果步骤4或步骤5的元数据显示更好的选择,可以使用不同的GAV重新运行:
bash
bash scripts/pick_connector.sh sfdc com.mulesoft.connectors:mule-salesforce-connector:11.1.0
bash scripts/pick_connector.sh slack com.mulesoft.connectors:mule4-slack-connector:2.0.1
bash scripts/pick_connector.sh jms org.mule.connectors:mule-jms-connector:1.10.3→ tmp/connector-choices/{sfdc,slack,jms}.json now each contain {groupId, assetId, version}
→ tmp/connector-choices/{sfdc,slack,jms}.json现在各包含{groupId, assetId, version}
If you realize after Step 4's metadata digest that the draft is wrong, re-run `pick_connector.sh` with the corrected GAV. Drafts remain mutable until Step 8's `commit_connectors.sh` promotes them.
**Why drafts instead of pins during Phase 1.** If a connector choice bakes into `tmp/connector-versions/` before the user has seen the Technical Design Summary, the agent — and every downstream check — treats it as settled. Holding the choice as a draft until TDD approval keeps the whole design reversible, and lets the approval gate be the real commitment point.
如果在步骤4的元数据摘要后意识到草稿错误,使用正确的GAV重新运行`pick_connector.sh`。草稿在步骤8的`commit_connectors.sh`升级前保持可变。
**为什么在第一阶段使用草稿而非固定项**。如果在用户看到技术设计摘要前,连接器选择就被写入`tmp/connector-versions/`,代理——以及所有下游检查——会将其视为已确定。在TDD批准前将选择保留为草稿,使整个设计保持可逆,并让批准关卡成为真正的承诺点。Selection rules the script applies internally
脚本内部应用的选择规则
(Reference only — you don't need to reimplement them. The list is ordered best-guess-first; treat ordering as a soft hint, not a directive.)
- Only (Mule 4 compatible) — Mule 3
"type": "extension"assets, templates, examples, and rest-apis are filtered out.type=connector - Any groupId whose asset is is admissible; ranking keeps first-party connectors on top via a 3-tier preference (
type="extension">com.mulesoft.connectors> other).org.mule.connectors - Latest semantic version within each group.
(groupId, assetId) - Token-overlap scoring with the search term; the premium groupId and shorter assetId break ties. Scores are used for ordering only and are never emitted.
- Two pages fetched in parallel (offsets 0 and 200) so broad searches like don't drop candidates off a single page.
salesforce
(仅供参考——你无需重新实现。列表按最佳猜测排序;将排序视为软提示,而非指令。)
- 仅选择(兼容Mule 4)——过滤掉Mule 3的
"type": "extension"资产、模板、示例和rest-apis。type=connector - 任何资产为的groupId都可接受;排序通过三层偏好将第一方连接器放在顶部(
type="extension">com.mulesoft.connectors> 其他)。org.mule.connectors - 每个组内的最新语义版本。
(groupId, assetId) - 与搜索词的标记重叠评分;高级groupId和更短的assetId用于打破平局。分数仅用于排序,不会输出。
- 并行获取两页(偏移量0和200),因此像这样的宽泛搜索不会遗漏单页之外的候选。
salesforce
Common search terms
常见搜索术语
These are starting hints for well-known systems. For anything else — and especially for any system you suspect the user's org may have a private connector for — search by system name first.
| System | Search term |
|---|---|
| Salesforce | |
| Database | |
| HTTP | |
| NetSuite | |
| ServiceNow | |
| Amazon S3 | |
| JMS | |
| Slack | |
For any system not in the list, search dynamically with the system name (e.g. , , , , ) — don't assume naming patterns and don't assume the system has no connector. Broader system-name terms also surface any private (UUID-groupId) connectors the user's organization has published in the same domain, which a narrow term tends to miss.
stripeshopifyhubspotdatabrickssnowflakemule-<name>-connector这些是知名系统的起始提示。对于其他任何系统——尤其是你怀疑用户组织可能有私有连接器的系统——先按系统名称搜索。
| 系统 | 搜索术语 |
|---|---|
| Salesforce | |
| Database | |
| HTTP | |
| NetSuite | |
| ServiceNow | |
| Amazon S3 | |
| JMS | |
| Slack | |
对于列表中未包含的任何系统,动态使用系统名称搜索(例如、、、、)——不要假设命名模式,不要假设系统没有连接器。更宽泛的系统名称术语还会显示用户组织在同一领域发布的任何私有(UUID-groupId)连接器,而窄的术语往往会错过这些。
stripeshopifyhubspotdatabrickssnowflakemule-<name>-connectorStep 4: Describe Connectors
步骤4:描述连接器
For each connector resolved in Step 3, retrieve its full metadata and read the digest that the wrapper script prints. Use rather than writing the pipeline by hand — the wrapper resolves the probe path, saves the full JSON to disk for later steps, AND echoes and to stdout so you see what Step 5 will need:
describe_connector.shdescribe-connectorsources[]configs[]bash
bash scripts/describe_connector.sh sfdc # nickname from Step 3
bash scripts/describe_connector.sh stripe
bash scripts/describe_connector.sh httpEach invocation writes (full response, consumed again by Phase 2) and prints a digest shaped like this:
tmp/connector-metadata/<nickname>.jsonjson
{
"namespace_prefix": "stripe",
"sources": [
"on-canceled-subscription-listener",
"on-new-charge-listener",
...
],
"configs": [
{ "name": "config", "providers": ["api-key"] }
],
"operations_count": 335,
"operations_sample": ["createV13dSecure", "..."]
}Read the array that comes back. That list is the set of real native triggers the connector supports; it is what Step 5 branches on. Do not skip past the digest straight to the next call — Step 5's trigger decision depends on you knowing which sources each connector exposes, and the digest is the cheapest place to get that information.
sources[]describe_connector.shThe script also writes with the connector-wide error-type whitelist. The Step 16 validator reads this directory; you don't need to invoke it manually.
tmp/connector-errors/<nickname>.jsonIf you ever need the full response (e.g. to introspect for ), read directly.
childElements[]oauth-callback-configtmp/connector-metadata/<nickname>.jsonManual fallback — if for some reason the wrapper is unavailable, you can reproduce it by hand. In Phase 1 the draft file is authoritative; accepts either location:
build_gav.shbash
NODE_NO_WARNINGS=1 anypoint-cli-v4 dx mule describe-connector \
--connector "$(bash scripts/build_gav.sh tmp/connector-choices/sfdc.json)" \
--output json > tmp/connector-metadata/sfdc.json
jq '{namespace: .namespace.prefix, sources, configs: [.configs[] | {name, providers: [.connectionProviders[]?]}]}' tmp/connector-metadata/sfdc.jsonBut in the common case prefer the wrapper — it is one line instead of three and it makes the sources list visible in your turn's tool output without a follow-up call.
对于步骤3中解析的每个连接器,检索其完整元数据并读取包装脚本打印的摘要。使用而非手动编写管道——包装脚本会解析探测路径,将完整JSON保存到磁盘供后续步骤使用,并将和输出到stdout,以便你看到步骤5需要的内容:
describe_connector.shdescribe-connectorsources[]configs[]bash
bash scripts/describe_connector.sh sfdc # 步骤3中的昵称
bash scripts/describe_connector.sh stripe
bash scripts/describe_connector.sh http每次调用都会将完整响应写入(第二阶段会再次使用),并打印如下形状的摘要:
tmp/connector-metadata/<nickname>.jsonjson
{
"namespace_prefix": "stripe",
"sources": [
"on-canceled-subscription-listener",
"on-new-charge-listener",
...
],
"configs": [
{ "name": "config", "providers": ["api-key"] }
],
"operations_count": 335,
"operations_sample": ["createV13dSecure", "..."]
}读取返回的数组。该列表是连接器支持的真实原生触发器集合;这是步骤5分支的依据。不要跳过摘要直接进行下一次调用——步骤5的触发器决策依赖于你知道每个连接器暴露的源,而摘要是获取该信息最便捷的地方。
sources[]describe_connector.sh脚本还会将连接器范围的错误类型白名单写入。步骤16的验证器会读取此目录;你无需手动调用。
tmp/connector-errors/<nickname>.json如果需要完整响应(例如,内省中的),直接读取即可。
childElements[]oauth-callback-configtmp/connector-metadata/<nickname>.json手动回退——如果包装脚本因某种原因不可用,你可以手动重现。在第一阶段,草稿文件是权威的;接受任一位置:
build_gav.shbash
NODE_NO_WARNINGS=1 anypoint-cli-v4 dx mule describe-connector \
--connector "$(bash scripts/build_gav.sh tmp/connector-choices/sfdc.json)" \
--output json > tmp/connector-metadata/sfdc.json
jq '{namespace: .namespace.prefix, sources, configs: [.configs[] | {name, providers: [.connectionProviders[]?]}]}' tmp/connector-metadata/sfdc.json但在常见情况下,优先使用包装脚本——它只需一行,而非三行,并且无需后续调用即可在你的回合工具输出中显示源列表。
Step 5: Select Trigger
步骤5:选择触发器
Every top-level flow (that is not a sub-flow or a target) needs exactly ONE trigger. Step 5 decides which trigger by letting connector metadata drive the choice — not prompt-text intuition.
<flow-ref>[BLOCKER] Explore-before-decide gate. Before committing to a trigger — whether inline or via — both of the following must be true for EVERY named system from Step 2's Systems list:
AskUserQuestion- exists on disk (Step 3, via
tmp/connector-choices/<nick>.json).pick_connector.sh - exists on disk (Step 4).
tmp/connector-metadata/<nick>.json
AND you must have the content in view. Run:
sources[]bash
for f in tmp/connector-metadata/*.json; do
echo "--- $f ---"
jq '{namespace: .namespace.prefix, sources}' "$f"
donein the response that begins Step 5, and read the output. This is the same data the digest already showed per connector in Step 4, but re-echoing it here puts every connector's sources side-by-side in one place right before the decision. Do not commit to a trigger without having those lists in the current tool output — past turns scroll out of context quickly.
describe_connector.shWhy this gate exists: if the agent commits to a trigger before reading , the usual failure mode is to default to (treating the prompt as a webhook) and silently ignore a real connector source that Step 4 just fetched. A connector's array is the authoritative list of triggers it supports; Step 5 must branch from that list, not from prompt-text intuition.
sources[]http:listenersources[]每个顶级流(不是子流或目标)恰好需要一个触发器。步骤5通过让连接器元数据驱动选择来决定使用哪个触发器——而非提示文本直觉。
<flow-ref>[阻塞点] 先探索后决策关卡。在提交触发器选择之前——无论是内联还是通过——步骤2系统列表中的每个命名系统必须满足以下两个条件:
AskUserQuestion- 存在于磁盘上(步骤3,通过
tmp/connector-choices/<nick>.json)。pick_connector.sh - 存在于磁盘上(步骤4)。
tmp/connector-metadata/<nick>.json
并且你必须查看内容。运行:
sources[]bash
for f in tmp/connector-metadata/*.json; do
echo "--- $f ---"
jq '{namespace: .namespace.prefix, sources}' "$f"
done在开始步骤5的响应中运行此命令,并读取输出。这与步骤4中摘要为每个连接器显示的数据相同,但在此处重新输出会将每个连接器的源并排放在一个地方,就在决策之前。不要在当前工具输出中没有这些列表的情况下提交触发器选择——之前的回合会很快滚出上下文。
describe_connector.sh此关卡存在的原因:如果代理在读取之前就提交触发器选择,通常的失败模式是默认使用(将提示视为Webhook),并静默忽略步骤4刚刚获取的真实连接器源。连接器的数组是其支持的触发器的权威列表;步骤5必须从此列表分支,而非提示文本直觉。
sources[]http:listenersources[]Decision ladder (evaluate in order)
决策阶梯(按顺序评估)
Work through the rungs below in order. Each rung is one of the possible paths — there is no "fallback" ranking; the first path whose preconditions all match is the one you take.
按顺序处理以下阶梯。每个阶梯是一种可能的路径——没有“回退”排名;第一个所有前提条件都匹配的路径就是你要采取的路径。
Rung 1 — Connector-source path
阶梯1 — 连接器源路径
For each connector in scope, examine from the digest. For any source whose name plausibly relates to the user's stated need (noun match: "product", "order", "charge", "customer"; AND verb-prefix consistency: , , , , , , ), inspect its shape via the unified command with :
sources[]on-new-*on-updated-*on-modified-*on-*-arrivedpoll-**-listener*-triggerdescribe-connector--type sourcebash
NODE_NO_WARNINGS=1 anypoint-cli-v4 dx mule describe-connector \
--connector "$(bash scripts/build_gav.sh tmp/connector-choices/<nick>.json)" \
--type source \
--name <source-name> \
--output jsonDo not call on every source — only on those whose name plausibly fits the user's intent per the noun+verb-prefix check above. On rich connectors this is the difference between 1–2 CLI calls and 7+ (Shopify, Salesforce, etc.).
source-detailCompare the returned shapes — not the names alone — to the user's intent:
- If the source's includes a
childElements[]element, this is a polling source — the connector itself handles the cadence natively. When the user's prompt names a cadence ("every N", "daily", "hourly") AND the matched source is a polling source, the cadence goes inside the source'sscheduling-strategychild. Do NOT introduce a separate top-level<scheduling-strategy>alongside it. Example correct shape:<scheduler>xml<shopify:on-updated-product-trigger config-ref="shopifyConfig"> <scheduling-strategy> <fixed-frequency frequency="3000" startDelay="5000"/> </scheduling-strategy> </shopify:on-updated-product-trigger> - If the source has no child and exposes an event (
scheduling-strategy,on-new-*), it's an event source — use it directly; no top-level scheduler needed.on-modified-* - If the source's shape includes references, it's a webhook receiver — suitable for "receive callback at endpoint" prompts.
listenerConfig
Commit inline to a connector source when exactly one source's shape fits the user's intent and the match is explainable in one sentence. State the choice with a one-line rationale citing the source name.
Prompt via when two or more sources both pass the shape check against the user's intent, OR when the user's language is genuinely ambiguous about which source semantics they want. Options list the real source names, not generic placeholders:
AskUserQuestionxml
<ask_followup_question>
<question>Which Salesforce event should trigger this flow?</question>
<options>[
"salesforce:replay-topic-listener — subscribe to a Salesforce streaming topic",
"salesforce:modified-object-listener — fire when a record of a given sObject is modified",
"Other — pick a different source"
]</options>
</ask_followup_question>If no source passes the shape check against any connector in scope, move to Rung 2.
对于每个范围内的连接器,检查摘要中的。对于任何名称似乎与用户需求相关的源(名词匹配:“product”、“order”、“charge”、“customer”;并且动词前缀一致:、、、、、、),通过带有的统一命令检查其形状:
sources[]on-new-*on-updated-*on-modified-*on-*-arrivedpoll-**-listener*-trigger--type sourcedescribe-connectorbash
NODE_NO_WARNINGS=1 anypoint-cli-v4 dx mule describe-connector \
--connector "$(bash scripts/build_gav.sh tmp/connector-choices/<nick>.json)" \
--type source \
--name <source-name> \
--output json不要对每个源调用——仅对那些名称根据名词+动词前缀检查似乎符合用户意图的源调用。对于丰富的连接器,这是1–2次CLI调用与7+次调用的区别(Shopify、Salesforce等)。
source-detail将返回的形状——而非仅名称——与用户意图进行比较:
- 如果源的包含
childElements[]元素,则这是一个轮询源——连接器本身原生处理节奏。当用户提示命名了节奏(“每N”、“每日”、“每小时”)且匹配的源是轮询源时,节奏应放在源的scheduling-strategy子元素内。不要单独引入顶级<scheduling-strategy>。正确示例形状:<scheduler>xml<shopify:on-updated-product-trigger config-ref="shopifyConfig"> <scheduling-strategy> <fixed-frequency frequency="3000" startDelay="5000"/> </scheduling-strategy> </shopify:on-updated-product-trigger> - 如果源没有子元素且暴露事件(
scheduling-strategy、on-new-*),则是事件源——直接使用;无需顶级调度器。on-modified-* - 如果源的形状包含引用,则是Webhook接收器——适用于“在端点接收回调”的提示。
listenerConfig
内联提交连接器源:当恰好一个源的形状符合用户意图,且匹配可以用一句话解释时。用一句话说明选择,引用源名称。
通过提示:当两个或多个源都通过形状检查符合用户意图,或者用户的语言确实对他们想要的源语义模糊时。选项列出真实的源名称,而非通用占位符:
AskUserQuestionxml
<ask_followup_question>
<question>此流应使用哪个Salesforce事件作为触发器?</question>
<options>[
"salesforce:replay-topic-listener — 订阅Salesforce流主题",
"salesforce:modified-object-listener — 当给定sObject的记录被修改时触发",
"其他 — 选择不同的源"
]</options>
</ask_followup_question>如果没有源通过范围内任何连接器的形状检查,则进入阶梯2。
Rung 2 — Generic scheduler path
阶梯2 — 通用调度器路径
Take this path when:
- No connector source fits the user's intent (Rung 1 examined the candidates and none matched), AND
- The prompt names a cadence ("every N", "daily", "hourly", "poll every…"), AND
- The flow body will call connector operations (not event-driven).
Use with or . State the choice inline.
<scheduler><fixed-frequency><cron>Record the rejection. When taking this path, note in one sentence why Rung 1's sources were rejected — e.g. "Shopify's matches 'every 3 seconds' but the user wants to pull by custom date range not 'updated since last poll', so a generic + is more appropriate." Step 7's TDD requires this list; capture it now while the reasoning is fresh.
on-updated-product-trigger<scheduler>shopify:product-list在以下情况下采用此路径:
- 没有连接器源符合用户意图(阶梯1检查了候选,但没有匹配),并且
- 提示命名了节奏(“每N”、“每日”、“每小时”、“每隔…轮询”),并且
- 流主体将调用连接器操作(非事件驱动)。
使用带有或的。内联说明选择。
<fixed-frequency><cron><scheduler>记录拒绝原因。采用此路径时,用一句话说明为什么阶梯1的源被拒绝——例如,“Shopify的匹配‘每3秒’的意图,但用户希望按自定义日期范围拉取,而非‘自上次轮询后更新’,因此通用 + 更合适。”步骤7的TDD需要此列表;现在就记录,因为推理还清晰。
on-updated-product-trigger<scheduler>shopify:product-listRung 3 — HTTP Listener path
阶梯3 — HTTP监听器路径
Take this path when:
- The prompt explicitly says "expose endpoint", "receive HTTP request", "provide REST API", "webhook at /path", AND
- No connector source in scope is a webhook-style receiver.
Use . State the choice inline. Record which connector sources were considered and why they were rejected (see Step 7).
<http:listener>在以下情况下采用此路径:
- 提示明确说“暴露端点”、“接收HTTP请求”、“提供REST API”、“在/path处设置Webhook”,并且
- 范围内没有连接器源是Webhook风格的接收器。
使用。内联说明选择。记录考虑过的连接器源以及拒绝它们的原因(请参阅步骤7)。
<http:listener>Rung 4 — Ask the user
阶梯4 — 询问用户
Take this path when none of Rungs 1–3 clearly apply — e.g. the prompt is outbound-only ("makes a request", "fetches", "retrieves") with no cadence and no endpoint language. with options derived from the actual of connectors in scope PLUS Scheduler and HTTP Listener:
AskUserQuestionsources[]xml
<ask_followup_question>
<question>The prompt describes outbound calls but does not name a trigger. What should start this flow?</question>
<options>[
"Scheduler — run on a time-based schedule",
"HTTP Listener — receive an inbound HTTP request",
"<connector>:<source-name> — native event from one of the connectors in scope (list any that apply based on sources[])",
"Other — please describe"
]</options>
</ask_followup_question>在阶梯1–3均不明确适用时采用此路径——例如,提示仅描述出站操作(“发起请求”、“获取”、“检索”),无节奏和端点语言。使用,选项来自范围内连接器的实际加上调度器和HTTP监听器:
AskUserQuestionsources[]xml
<ask_followup_question>
<question>提示描述了出站调用,但未命名触发器。应如何启动此流?</question>
<options>[
"调度器 — 按时间计划运行",
"HTTP监听器 — 接收入站HTTP请求",
"<connector>:<source-name> — 范围内某个连接器的原生事件(根据sources[]列出适用的)",
"其他 — 请描述"
]</options>
</ask_followup_question>After the decision
决策后
Record the selected trigger, its owning connector (if any), and — if the path is Rung 2 or Rung 3 — the list of connector sources that were considered and one-line reasons each was dismissed. Step 7's TDD surfaces this list; if it is missing, the TDD is incomplete and Phase 2 cannot start.
[BLOCKER] WAIT for the user's response before moving to Step 6 when this step prompts.
记录所选触发器、其所属连接器(如果有)——如果路径是阶梯2或阶梯3,记录考虑过的连接器源列表以及每个源被拒绝的一句话原因。步骤7的TDD会显示此列表;如果缺失,TDD不完整,第二阶段无法启动。
[阻塞点] 如果此步骤提示,请等待用户响应后再进入步骤6。
Step 6: Select Connection Providers
步骤6:选择连接提供商
Ask the user only when there is an actual choice to make. For each connector, look at the metadata captured in Step 4 — specifically the list of the config that owns the operation you intend to call in Phase 2.
configs[]connectionProvidersDecision rule:
- Multiple configs or multiple providers → MUST use . The user's choice determines both which
AskUserQuestionand whichconfig-nameyou pass to Step 11's--connection-providercall, and which XML structure you write in Step 12.config-detail - Exactly one config and exactly one provider → DO NOT prompt. State the choice inline in one line ("Using — the only option provided by the connector") and proceed. Prompts that offer a single "option" look like pointless ceremony and waste a conversation turn.
s3:config[connection]
Worked examples from live Exchange metadata:
| Connector | | Action |
|---|---|---|
| S3 connector | | Announce, do NOT prompt |
| VM connector | | Announce, do NOT prompt |
| HTTP connector | | Configs map 1:1 to listener vs request — determined by the flow shape (trigger vs outbound call), not a user preference. Announce, do NOT prompt. |
| A multi-config connector with stream vs. non-stream configs | | Prompt — pick the config whose operations match the use case, and if that config has >1 provider, pick a provider. |
| A connector offering basic / OAuth / JWT / client-credentials | | Prompt — real alternatives with different credential models. |
| Database connector | | Prompt for the provider, then resolve the JDBC driver GAV in the same step (see "Step 6b — JDBC driver resolution" below). Step 9 is a mechanical |
When you do prompt, present only the real alternatives (don't pad with "if unsure..." copy). Example:
This connector offers four connection providers. Which should this integration use?
— username + password + security tokenbasic — OAuth with user credentialsoauth-user-pass — JWT bearer token (server-to-server)jwt — OAuth client credentialsoauth-client-credentials
Do not offer a "recommendation" as one of the options if it's really the only option. If there is only one choice, do not ask.
Store the selected pair for each connector, and persist the connection-provider output for Phase 2 so it doesn't have to re-invoke the CLI. Flag semantics note: carries the connection provider name, carries the config name — easy to get backwards:
(config-name, connection-provider)describe-connector--name--config-namebash
NODE_NO_WARNINGS=1 anypoint-cli-v4 dx mule describe-connector \
--connector "$(bash scripts/build_gav.sh tmp/connector-choices/sfdc.json)" \
--type connection-provider \
--name basic-connection \
--config-name sfdc-config \
--output json > tmp/connector-metadata/sfdc-config.json仅当存在实际选择时才询问用户。对于每个连接器,查看步骤4中捕获的元数据——特别是你打算在第二阶段调用的操作所属配置的列表。
configs[]connectionProviders决策规则:
- 多个配置或多个提供商 → 必须使用。用户的选择决定了你在步骤11的
AskUserQuestion调用中传递的config-detail和config-name,以及你在步骤12中编写的XML结构。--connection-provider - 恰好一个配置和恰好一个提供商 → 不要提示。用一句话内联说明选择(“使用— 连接器提供的唯一选项”),然后继续。提供单一“选项”的提示看起来像无意义的仪式,会浪费对话回合。
s3:config[connection]
来自实时Exchange元数据的示例:
| 连接器 | | 操作 |
|---|---|---|
| S3连接器 | | 宣布,不要提示 |
| VM连接器 | | 宣布,不要提示 |
| HTTP连接器 | | 配置与监听器vs请求流形状一一对应,而非用户偏好。宣布,不要提示 |
| 带有流与非流配置的多配置连接器 | | 提示 — 选择操作符合用例的配置;如果该配置有多个提供商,选择一个提供商。 |
| 提供基础/OAuth/JWT/客户端凭证的连接器 | | 提示 — 具有不同凭证模型的真实替代方案。 |
| Database连接器 | | 提示选择提供商,然后在同一步骤中解析JDBC驱动GAV(请参阅下面的“步骤6b — JDBC驱动解析”)。步骤9是对 |
当你提示时,仅呈现真实替代方案(不要添加“如果不确定…”的内容)。示例:
此连接器提供四个连接提供商。此集成应使用哪一个?
— 用户名 + 密码 + 安全令牌basic — 使用用户凭证的OAuthoauth-user-pass — JWT承载令牌(服务器到服务器)jwt — OAuth客户端凭证oauth-client-credentials
如果实际上只有一个选项,不要将“推荐”作为选项之一。如果只有一个选择,不要询问。
存储每个连接器的选定对,并持久化连接提供商输出供第二阶段使用,这样就无需重新调用CLI。标志语义注意: 是连接提供商名称,是配置名称——很容易弄反:
(config-name, connection-provider)describe-connector--name--config-namebash
NODE_NO_WARNINGS=1 anypoint-cli-v4 dx mule describe-connector \
--connector "$(bash scripts/build_gav.sh tmp/connector-choices/sfdc.json)" \
--type connection-provider \
--name basic-connection \
--config-name sfdc-config \
--output json > tmp/connector-metadata/sfdc-config.jsonStep 6b — JDBC driver resolution (only if mule-db-connector
is in scope)
mule-db-connector步骤6b — JDBC驱动解析(仅当mule-db-connector
在范围内时)
mule-db-connectormule-db-connector<db:my-sql-connection><db:generic-connection><sharedLibrary>groupId:artifactId:versionpom.xmlBranch on the Step-6 provider answer:
| Provider picked | Driver auto-pin from the canonical table (Step 9) | Prompt? |
|---|---|---|
| | No — announce inline |
| | No — announce inline |
| | No — announce inline |
| | No — announce inline |
| Cannot auto-pin — | Yes |
| Cannot auto-pin — driver is supplied by the container, or by an explicit | Yes |
| Multi-artifact + JDK-dependent — If selected, see | Yes |
The rule: if the target database is one of the first rows above (my-sql, oracle, mssql or generic with postgres) do not prompt — auto-pin and announce inline. Reserve the prompt for non-canonical targets and for the inherently multi-choice providers (, ).
genericdata-sourcederbyThe always-prompt branches all use the same prompt shape:
xml
<ask_followup_question>
<question>You picked <provider> for <database>; which JDBC driver should ship as a sharedLibrary?</question>
<options>[
"<canonical-option-1 from the reference file> — <one-line purpose>",
"<canonical-option-2> — ...",
"Other — I will provide a groupId:artifactId:version"
]</options>
</ask_followup_question>What Step 6 must record for Step 9:
One or more tuples, plus the driver class, persisted so Step 9 can emit the + pairs without re-asking. Use a sidecar file next to the connector choice:
{groupId, artifactId, version}<dependency><sharedLibrary>bash
undefinedmule-db-connector<db:my-sql-connection><db:generic-connection><sharedLibrary>groupId:artifactId:versionpom.xml根据步骤6提供商答案分支:
| 选择的提供商 | 从规范表自动固定驱动(步骤9) | 是否提示? |
|---|---|---|
| | 否 — 内联宣布 |
| | 否 — 内联宣布 |
| | 否 — 内联宣布 |
| | 否 — 内联宣布 |
| 无法自动固定 — | 是 |
| 无法自动固定 — 驱动由容器提供,或通过显式 | 是 |
| 多工件+依赖JDK — 如果选择,请参阅 | 是 |
规则:如果目标数据库是上面前几行中的一个(my-sql、oracle、mssql或generic+postgres),不要提示——自动固定并内联宣布。仅对非规范目标和固有多选提供商(、)保留提示。
genericdata-sourcederby所有需要提示的分支使用相同的提示形状:
xml
<ask_followup_question>
<question>你为<database>选择了<provider>;应将哪个JDBC驱动作为sharedLibrary部署?</question>
<options>[
"<参考文件中的规范选项1> — <一句话用途>",
"<规范选项2> — ...",
"其他 — 我将提供groupId:artifactId:version"
]</options>
</ask_followup_question>步骤6必须为步骤9记录的内容:
一个或多个元组,加上驱动类,持久化以便步骤9可以输出 + 对,无需重新询问。在连接器选择旁边使用辅助文件:
{groupId, artifactId, version}<dependency><sharedLibrary>bash
undefinedexample: after Step 6 picks my-sql
示例:步骤6选择my-sql后
cat > tmp/connector-choices/db-driver.json <<'JSON'
{
"dependencies": [
{ "groupId": "com.mysql", "artifactId": "mysql-connector-j", "version": "8.4.0" }
],
"driverClass": "com.mysql.cj.jdbc.Driver"
}
JSON
For `derby:embedded` that file contains three entries; for `generic` with PostgreSQL it contains one. The Step-9 applier reads this file and applies every entry in it to `pom.xml`.
The driver choice will be part of the technical design. Step 7 shows it under "Build-time additions"; the user's approval at Step 7 is what authorizes Step 9 to edit `pom.xml`.
---cat > tmp/connector-choices/db-driver.json <<'JSON'
{
"dependencies": [
{ "groupId": "com.mysql", "artifactId": "mysql-connector-j", "version": "8.4.0" }
],
"driverClass": "com.mysql.cj.jdbc.Driver"
}
JSON
对于`derby:embedded`,该文件包含三个条目;对于`generic+PostgreSQL`,包含一个条目。步骤9的应用程序读取此文件,并将每个条目应用到`pom.xml`。
驱动选择将成为技术设计的一部分。步骤7在“构建时添加项”下显示它;用户在步骤7的批准授权步骤9编辑`pom.xml`。
---Step 7: Present Technical Design Summary
步骤7:呈现技术设计摘要
[BLOCKER] Present ONLY after Steps 1–6 are complete. Every connector must have a drafted GAV (from ), every connector must have captured metadata (from ), and every config must have a selected provider. If any of those is missing, go back to the relevant step — do not paper over with "TBD" in the summary.
tmp/connector-choices/*.jsontmp/connector-metadata/*.json**Technical Design Summary**
**User Requirement:** "<original user prompt, verbatim>"
**Project Context:**
- Project directory: <absolute path where Phase 2 will create the project>
- Work type: <New / Modification / Post-scaffolding>
- Mule runtime: <mule_version from tmp/mule-dev-env.json>
- Java: <java_version>
**Trigger:**
- Selected: <element name> from <connector or built-in source>
(e.g., "shopify:on-updated-product-trigger with fixed-frequency 3000ms" or "salesforce:replay-topic-listener from mule-salesforce-connector:10.15.7" or "Built-in Scheduler, every 5 minutes")
- Sources considered: list the `sources[]` entries that were examined via `source-detail` (if any), with one line each
stating why the source was chosen OR dismissed. If the selected trigger is `<scheduler>` or `<http:listener>` and any
in-scope connector has a `sources[]` entry, at least one rejection line is required — a TDD whose "Sources considered"
is empty while a connector source exists is incomplete, and Phase 2 cannot start.
Example:
- `shopify:on-updated-product-trigger` — SELECTED: polling source with `scheduling-strategy` child, matches "every 3 seconds" intent.
- `shopify:on-new-product-trigger` — dismissed: fires only on creation, user wants updates too.
- `shopify:on-updated-customer-trigger` — dismissed: wrong object (product, not customer).
**Required Connectors:**
1. <System Name>: <GAV> [com.mulesoft.connectors | org.mule.connectors | third-party]
- Purpose: <one line>
- Config: <config-name> | Provider: <provider-name>
2. ...
**Build-time additions (auto):**
- `mule-http-connector` — included if the trigger is HTTP Listener OR any Step 6 provider is OAuth-family (callback listener)
- JDBC driver(s) — included if `mule-db-connector` is in scope. List **every** `groupId:artifactId:version` recorded in `tmp/connector-choices/db-driver.json` from Step 6b, plus the driver class. Vague phrasing like "PostgreSQL JDBC driver included" is not acceptable here — the user is approving an explicit build edit and needs the exact coordinates.
Example:
- `org.postgresql:postgresql:42.7.11` (driver class `org.postgresql.Driver`) — added as `<dependency>` and `<sharedLibrary>` in `pom.xml`.
**Built-in processors anticipated (if applicable):**
- DataWeave, Logger, error handlersThen ask for explicit approval:
xml
<ask_followup_question>
<question>Please review the technical design above. Proceed to build (Phase 2)?</question>
<options>[
"Yes, proceed to build.",
"No, I want to change the plan.",
"No, cancel generation."
]</options>
</ask_followup_question>[BLOCKER] WAIT for explicit "Yes, proceed to build." before Step 8. On "No, I want to change the plan.", ask which part (trigger, connectors, providers) and loop back to the relevant step. On "No, cancel generation.", stop the workflow politely.
Why this gate matters: Phase 1 is the last chance to catch a silent HTTP fallback, a wrong connector variant, a wrong trigger, or a missing clarifying question. Once Phase 2 begins the project skeleton is on disk and rewinding is more expensive for everyone. The summary is the user's chance to correct course; respect "No, I want to change the plan." as a first-class outcome, not an exception.
After approval, the very first action of Step 8 is — that is the script that promotes every Phase-1 draft in to the pinned directory that and will read from. Do not skip it; / calls later in Phase 2 will fail if the pin files aren't there.
commit_connectors.shtmp/connector-choices/tmp/connector-versions/dx mule project createpom.xmlbuild_deps.shbuild_gav.shOutput: User approval to proceed.
[阻塞点] 仅在步骤1–6完成后呈现。每个连接器必须有一个草稿GAV(来自),每个连接器必须有捕获的元数据(来自),每个配置必须有选定的提供商。如果任何一项缺失,返回相关步骤——不要在摘要中用“TBD”掩盖。
tmp/connector-choices/*.jsontmp/connector-metadata/*.json**技术设计摘要**
**用户需求:** "<原始用户提示,原句>"
**项目上下文:**
- 项目目录:<第二阶段将创建项目的绝对路径>
- 工作类型:<新建/修改/脚手架后>
- Mule运行时:<来自tmp/mule-dev-env.json的mule_version>
- Java:<java_version>
**触发器:**
- 选定:<元素名称>来自<连接器或内置源>
(例如:"shopify:on-updated-product-trigger,固定频率3000ms"或"salesforce:replay-topic-listener来自mule-salesforce-connector:10.15.7"或"内置调度器,每5分钟")
- 考虑的源:列出通过`source-detail`检查的`sources[]`条目(如果有),每个条目用一句话说明选择或拒绝的原因。如果选定的触发器是`<scheduler>`或`<http:listener>`,且范围内任何连接器有`sources[]`条目,则至少需要一条拒绝理由——如果“考虑的源”为空但存在连接器源,TDD不完整,第二阶段无法启动。
示例:
- `shopify:on-updated-product-trigger` — 已选择:带`scheduling-strategy`子元素的轮询源,匹配“每3秒”的意图。
- `shopify:on-new-product-trigger` — 已拒绝:仅在创建时触发,用户需要更新。
- `shopify:on-updated-customer-trigger` — 已拒绝:错误对象(产品,而非客户)。
**所需连接器:**
1. <系统名称>:<GAV> [com.mulesoft.connectors | org.mule.connectors | 第三方]
- 用途:<一句话>
- 配置:<config-name> | 提供商:<provider-name>
2. ...
**构建时添加项(自动):**
- `mule-http-connector` — 如果触发器是HTTP监听器,或任何步骤6提供商属于OAuth家族(回调监听器),则包含
- JDBC驱动 — 如果`mule-db-connector`在范围内,则包含。列出步骤6b中记录在`tmp/connector-choices/db-driver.json`中的**每个**`groupId:artifactId:version`,加上驱动类。此处不接受模糊表述,如“包含PostgreSQL JDBC驱动”——用户正在批准明确的构建编辑,需要确切的坐标。
示例:
- `org.postgresql:postgresql:42.7.11`(驱动类`org.postgresql.Driver`) — 在`pom.xml`中添加为`<dependency>`和`<sharedLibrary>`。
**预期的内置处理器(如适用):**
- DataWeave、Logger、错误处理器然后请求明确批准:
xml
<ask_followup_question>
<question>请审阅上述技术设计。是否继续构建(第二阶段)?</question>
<options>[
"是,继续构建。",
"否,我想更改计划。",
"否,取消生成。"
]</options>
</ask_followup_question>[阻塞点] 在步骤8之前等待明确的“是,继续构建。”。如果用户选择“否,我想更改计划。”,询问要更改的部分(触发器、连接器、提供商),并返回相关步骤。如果选择“否,取消生成。”,礼貌地停止工作流。
此关卡重要的原因:第一阶段是最后一次机会,可以发现静默HTTP回退、错误的连接器变体、错误的触发器或缺失的澄清问题。一旦第二阶段开始,项目骨架已在磁盘上,回退对每个人来说成本更高。摘要是用户纠正路线的机会;将“否,我想更改计划。”视为一等结果,而非异常。
批准后,步骤8的第一个操作是——此脚本将第一阶段中的所有草稿升级到固定的目录,和将从此目录读取。不要跳过此步骤;如果固定文件不存在,第二阶段后续的/调用将失败。
commit_connectors.shtmp/connector-choices/tmp/connector-versions/dx mule project createpom.xmlbuild_deps.shbuild_gav.sh输出: 用户批准继续。
Phase 2: Build
第二阶段:构建
Step 8: Create Project
步骤8:创建项目
First action — promote Phase 1 drafts to pinned versions. The user just approved the TDD, so every connector choice in is now official. Promote them in one shot:
tmp/connector-choices/bash
bash scripts/commit_connectors.sh第一个操作 — 将第一阶段草稿升级为固定版本。用户刚刚批准了TDD,因此中的每个连接器选择现在都是正式的。一次性升级:
tmp/connector-choices/bash
bash scripts/commit_connectors.sh→ copies every tmp/connector-choices/.json → tmp/connector-versions/.json
→ 将每个tmp/connector-choices/.json复制到tmp/connector-versions/.json
→ exits 1 if no drafts exist (means Step 3 was skipped for some system)
→ 如果没有草稿存在,退出码1(意味着某个系统跳过了步骤3)
Then read `tmp/mule-dev-env.json` for the Mule version and use `build_deps.sh` to emit the full `--dependencies` string from the pins on disk — do not retype GAVs from previous tool output, and do not inline `$(build_gav.sh ...)` once per connector:
```bash
MULE_VERSION=$(jq -r '.mule_version' tmp/mule-dev-env.json)
NODE_NO_WARNINGS=1 anypoint-cli-v4 dx mule project create <project-name> \
--group-id com.example \
--mule-version "$MULE_VERSION" \
--dependencies "$(bash scripts/build_deps.sh)"build_deps.shtmp/connector-versions/*.jsondb-driver.jsonhttp.jsonWhy one wrapper instead of N inlined substitutions: with absolute script paths (per the invocation rule above) each inlined is ~165 characters, so a 4-connector project produces a 1000+ character command. The Dev Agent terminal harness loses its completion marker on very long commands and stalls the whole turn until the 2-minute timeout fires. keeps the command under ~250 characters regardless of how many connectors are in scope.
$(build_gav.sh …)$(…)dx mule project createbuild_deps.shEvery connector that appears in the approved Technical Design Summary must have a pin in before runs — already put them there. Two cases add an extra connector beyond the systems explicitly named in the TDD:
tmp/connector-versions/build_deps.shcommit_connectors.sh| Condition | Added connector |
|---|---|
Step 5 selected trigger is HTTP Listener (flow contains | |
| Step 6 selected any OAuth-family provider (OAuth, JWT, auth-code) | |
Any event-listener source trigger (e.g., | None beyond the connector that owns the source — it is already in the TDD |
If either HTTP-trigger condition applies and you have not already picked HTTP in Step 3, run + + before so exists when scans the directory. Missing it causes a first-build failure like — self-healable, but it costs a turn.
get_latest_connector.sh mule-http-connector httppick_connector.sh http <gav>commit_connectors.shdx mule project createtmp/connector-versions/http.jsonbuild_deps.shCan't resolve http://www.mulesoft.org/schema/mule/http/current/mule-http.xsdVersion source-of-truth (from Step 3): every GAV in must come from a file. Do not inline a literal version like in the string — if you bypass and the literal version differs from what the helper would have returned, will fail with a "not found" error, and the failure is often not self-healable because the version is fictional.
--dependenciestmp/connector-versions/*.jsoncom.mulesoft.connectors:mule-amazon-s3-connector:6.6.0--dependenciesbuild_deps.shmvn clean packageProject structure created:
- (Maven configuration with dependencies)
pom.xml - (artifact metadata with correct Java version)
mule-artifact.json - (flow definition)
src/main/mule/<project-name>.xml - (configuration files)
src/main/resources/
然后从`tmp/mule-dev-env.json`读取Mule版本,并使用`build_deps.sh`从磁盘上的固定项输出完整的`--dependencies`字符串——不要从之前的工具输出重新输入GAV,也不要为每个连接器内联`$(build_gav.sh ...)`:
```bash
MULE_VERSION=$(jq -r '.mule_version' tmp/mule-dev-env.json)
NODE_NO_WARNINGS=1 anypoint-cli-v4 dx mule project create <project-name> \
--group-id com.example \
--mule-version "$MULE_VERSION" \
--dependencies "$(bash scripts/build_deps.sh)"build_deps.shtmp/connector-versions/*.jsondb-driver.jsonhttp.json为什么使用一个包装器而非N个内联替换: 使用绝对脚本路径(根据上面的调用规则),每个内联约165个字符,因此一个4连接器项目会生成1000+字符的命令。Dev Agent终端工具在处理超长命令时会丢失完成标记,导致整个回合停滞直到2分钟超时。无论范围内有多少连接器,都能将命令保持在~250字符以内。
$(build_gav.sh …)$(…)dx mule project createbuild_deps.sh每个出现在已批准技术设计摘要中的连接器,在运行前必须在中有一个固定项——已经将它们放在那里。有两种情况会在TDD中明确命名的系统之外添加额外的连接器:
build_deps.shtmp/connector-versions/commit_connectors.sh| 条件 | 添加的连接器 |
|---|---|
步骤5选择的触发器是HTTP监听器(流包含 | |
| 步骤6选择了任何OAuth家族提供商(OAuth、JWT、auth-code) | |
任何事件监听器源触发器(例如 | 除了拥有源的连接器之外无其他——它已在TDD中 |
如果任一HTTP触发条件适用,且您尚未在步骤3中选择HTTP,请在之前运行 + + ,以便扫描目录时存在。缺少它会导致首次构建失败,如——可以自我修复,但会浪费一个回合。
dx mule project createget_latest_connector.sh mule-http-connector httppick_connector.sh http <gav>commit_connectors.shbuild_deps.shtmp/connector-versions/http.jsonCan't resolve http://www.mulesoft.org/schema/mule/http/current/mule-http.xsd版本来源(来自步骤3): 中的每个GAV必须来自文件。不要在字符串中内联文字版本,如——如果您绕过且文字版本与辅助脚本返回的版本不同,会因“未找到”错误失败,且失败通常无法自我修复,因为版本是虚构的。
--dependenciestmp/connector-versions/*.json--dependenciescom.mulesoft.connectors:mule-amazon-s3-connector:6.6.0build_deps.shmvn clean package创建的项目结构:
- (带依赖项的Maven配置)
pom.xml - (带正确Java版本的工件元数据)
mule-artifact.json - (流定义)
src/main/mule/<project-name>.xml - (配置文件)
src/main/resources/
Step 9: Apply JDBC Driver to pom.xml
步骤9:将JDBC驱动应用到pom.xml
The driver GAVs were already chosen in Step 6b and approved by the user at Step 7. Step 9 reads and applies every entry to — one entry produces one block AND one block. Skip this step entirely if is not in scope.
tmp/connector-choices/db-driver.json<project-name>/pom.xml<dependency><sharedLibrary>mule-db-connectorIf is missing but is in scope, return to Step 6b — do NOT invent a driver here or assume prematurely.
tmp/connector-choices/db-driver.jsonmule-db-connectorFor every entry in 's array, add both:
db-driver.jsondependencies[]- inside
<dependency>, verbatim from the sidecar:<dependencies>
xml
<dependency>
<groupId>{groupId}</groupId>
<artifactId>{artifactId}</artifactId>
<version>{version}</version>
</dependency>- inside the
<sharedLibrary>mule-maven-plugin—<configuration><sharedLibraries>/groupIdcopied verbatim from theartifactIdabove (no version here).<dependency>
xml
<configuration>
<sharedLibraries>
<sharedLibrary>
<groupId>{groupId}</groupId>
<artifactId>{artifactId}</artifactId>
</sharedLibrary>
<!-- repeat for every entry in db-driver.json -->
</sharedLibraries>
</configuration>驱动GAV已在步骤6b中选择,并在步骤7中获得用户批准。步骤9读取,并将每个条目应用到——一个条目生成一个块和一个块。如果不在范围内,完全跳过此步骤。
tmp/connector-choices/db-driver.json<project-name>/pom.xml<dependency><sharedLibrary>mule-db-connector如果缺失但在范围内,返回步骤6b——不要在此处发明驱动或过早假设。
tmp/connector-choices/db-driver.jsonmule-db-connector对于的数组中的每个条目,添加两者:
db-driver.jsondependencies[]- 内的
<dependencies>,与辅助文件完全一致:<dependency>
xml
<dependency>
<groupId>{groupId}</groupId>
<artifactId>{artifactId}</artifactId>
<version>{version}</version>
</dependency>- 的
mule-maven-plugin内的<configuration><sharedLibraries>—<sharedLibrary>/groupId与上面的artifactId完全一致(此处无版本)。<dependency>
xml
<configuration>
<sharedLibraries>
<sharedLibrary>
<groupId>{groupId}</groupId>
<artifactId>{artifactId}</artifactId>
</sharedLibrary>
<!-- 对db-driver.json中的每个条目重复 -->
</sharedLibraries>
</configuration>Step 10: Verify HTTP Connector (OAuth/HTTP-Listener defensive check)
步骤10:验证HTTP连接器(OAuth/HTTP监听器防御性检查)
In v7, Step 8's already includes when Step 5 chose HTTP Listener or Step 6 chose an OAuth-family provider — because Phase 1's approved TDD made that visible. This step is a defensive no-op check in the common case: run the helper in case the TDD missed the HTTP addition for some reason.
--dependenciesmule-http-connectorSkip this step entirely when none of the selected providers match AND the trigger is not HTTP Listener. Running it as a "just to be safe" consumes a turn.
oauth|jwt|auth-code|authorization-codeFor the OAuth / HTTP-Listener case, run the idempotent helper:
bash
bash <skill-dir>/scripts/maybe_add_http_connector.sh \
--project ./<project-name> \
"oauth-user-pass" # one argument per Step-6 provider<skill-dir>SKILL.mdIf any provider argument matches , , , or (case-insensitive), the script:
oauthjwtauth-codeauthorization-code- Reuses if the agent already picked HTTP in Step 3, otherwise runs
<project-name>/tmp/connector-choices/http.jsonand drafts the top row viaget_latest_connector.sh mule-http-connector http— HTTP is an unambiguous search, so no user prompt is needed.pick_connector.sh http <gav> - Inserts a block before
<dependency>in</dependencies>(with<project-name>/pom.xml).<classifier>mule-plugin</classifier> - Is a no-op if the HTTP connector is already present.
Manual fallback — also add HTTP connector if: the connector documentation mentions "callback URL" or "redirect URI", or Step 11 shows an child element. Without HTTP connector the build fails with: .
config-detailoauth-callback-configThe content of element '<connector>:<connection-provider>' is not complete在v7中,当步骤5选择HTTP监听器或步骤6选择OAuth家族提供商时,步骤8的已包含——因为第一阶段已批准的TDD使其可见。此步骤在常见情况下是防御性无操作检查:运行辅助脚本,以防TDD因某种原因遗漏了HTTP添加。
--dependenciesmule-http-connector完全跳过此步骤:当没有选定的提供商匹配,且触发器不是HTTP监听器时。作为“以防万一”运行它会浪费一个回合。
oauth|jwt|auth-code|authorization-code对于OAuth/HTTP监听器情况,运行幂等辅助脚本:
bash
bash <skill-dir>/scripts/maybe_add_http_connector.sh \
--project ./<project-name> \
"oauth-user-pass" # 每个步骤6提供商一个参数<skill-dir>SKILL.md如果任何提供商参数匹配、、或(不区分大小写),脚本:
oauthjwtauth-codeauthorization-code- 如果代理已在步骤3中选择HTTP,重用;否则运行
<project-name>/tmp/connector-choices/http.json,并通过get_latest_connector.sh mule-http-connector http将顶部行记录为草稿——HTTP是明确的搜索,无需用户提示。pick_connector.sh http <gav> - 在的
<project-name>/pom.xml之前插入</dependencies>块(带<dependency>)。<classifier>mule-plugin</classifier> - 如果HTTP连接器已存在,则无操作。
手动回退——如果连接器文档提到“callback URL”或“redirect URI”,或步骤11的显示子元素,也添加HTTP连接器。没有HTTP连接器,构建会失败,错误为:。
config-detailoauth-callback-configThe content of element '<connector>:<connection-provider>' is not completeStep 11: Get Configuration Details
步骤11:获取配置详情
Phase 1 Step 6 already persisted output to . Read it from there:
config-detailtmp/connector-metadata/<nickname>-config.jsonbash
cat tmp/connector-metadata/sfdc-config.jsonOnly re-invoke the CLI if the cache file is missing (which should not happen if Phase 1 ran correctly). Flag semantics note: is the connection provider, is the config:
--name--config-namebash
NODE_NO_WARNINGS=1 anypoint-cli-v4 dx mule describe-connector \
--connector "$(bash scripts/build_gav.sh tmp/connector-versions/sfdc.json)" \
--type connection-provider \
--name basic-connection \
--config-name sfdc-config \
--output jsonResponse shape (same + pattern):
attributeschildElementsjson
{
"name": "sfdc-config",
"prefix": "salesforce",
"elementName": "sfdc-config",
"attributes": [ { "attributeName": "name", "required": true } ],
"childElements": [
{ "paramName": "expirationPolicy", "prefix": "salesforce", "elementName": "expiration-policy" }
],
"connectionProviders": [
{
"name": "basic-connection",
"prefix": "salesforce",
"elementName": "basic-connection",
"attributes": [
{ "attributeName": "username", "required": true },
{ "attributeName": "password", "required": true },
{ "attributeName": "securityToken", "required": true }
],
"childElements": [
{ "paramName": "reconnection", "prefix": "mule", "elementName": "reconnection" }
]
}
]
}Check BOTH attributes AND childElements of the selected connection provider:
bash
jq '.connectionProviders[0].childElements[] | select(.paramName == "oauthCallbackConfig")' tmp/connector-metadata/sfdc-config.jsonConnection providers use one of two patterns:
-
Attributes pattern (e.g., Salesforce basic-connection):xml
<salesforce:basic-connection username="${salesforce.username}" password="${salesforce.password}" securityToken="${salesforce.securityToken}" /> -
Child elements pattern (e.g., Slack OAuth):xml
<slack:slack-auth-connection> <slack:oauth-authorization-code consumerKey="${slack.consumerKey}" consumerSecret="${slack.consumerSecret}" /> </slack:slack-auth-connection>
When generating XML: if has items, use attributes on the connection element; if is empty but has items, use nested child elements. Never hardcode structure — always use the metadata.
attributesattributeschildElements第一阶段步骤6已将输出持久化到。从那里读取:
config-detailtmp/connector-metadata/<nickname>-config.jsonbash
cat tmp/connector-metadata/sfdc-config.json仅当缓存文件缺失时才重新调用CLI(如果第一阶段正确运行,这不应该发生)。标志语义注意: 是连接提供商,是配置:
--name--config-namebash
NODE_NO_WARNINGS=1 anypoint-cli-v4 dx mule describe-connector \
--connector "$(bash scripts/build_gav.sh tmp/connector-versions/sfdc.json)" \
--type connection-provider \
--name basic-connection \
--config-name sfdc-config \
--output json响应形状(与 + 模式相同):
attributeschildElementsjson
{
"name": "sfdc-config",
"prefix": "salesforce",
"elementName": "sfdc-config",
"attributes": [ { "attributeName": "name", "required": true } ],
"childElements": [
{ "paramName": "expirationPolicy", "prefix": "salesforce", "elementName": "expiration-policy" }
],
"connectionProviders": [
{
"name": "basic-connection",
"prefix": "salesforce",
"elementName": "basic-connection",
"attributes": [
{ "attributeName": "username", "required": true },
{ "attributeName": "password", "required": true },
{ "attributeName": "securityToken", "required": true }
],
"childElements": [
{ "paramName": "reconnection", "prefix": "mule", "elementName": "reconnection" }
]
}
]
}检查选定连接提供商的和:
attributeschildElementsbash
jq '.connectionProviders[0].childElements[] | select(.paramName == "oauthCallbackConfig")' tmp/connector-metadata/sfdc-config.json连接提供商使用两种模式之一:
-
属性模式(例如Salesforce basic-connection):xml
<salesforce:basic-connection username="${salesforce.username}" password="${salesforce.password}" securityToken="${salesforce.securityToken}" /> -
子元素模式(例如Slack OAuth):xml
<slack:slack-auth-connection> <slack:oauth-authorization-code consumerKey="${slack.consumerKey}" consumerSecret="${slack.consumerSecret}" /> </slack:slack-auth-connection>
生成XML时: 如果有项,在连接元素上使用属性;如果为空但有项,使用嵌套子元素。永远不要硬编码结构——始终使用元数据。
attributesattributeschildElementsStep 12: Create Configuration Files
步骤12:创建配置文件
Based on Step 11 metadata, create configuration files.
src/main/resources/config.yamlyaml
salesforce:
username: "user@example.com"
password: "password"
securityToken: "token"
slack:
consumerKey: "your-consumer-key"
consumerSecret: "your-consumer-secret"Configuration XML — structure driven entirely by metadata:
xml
<configuration-properties file="config.yaml" />
<salesforce:sfdc-config name="salesforceConfig">
<salesforce:basic-connection
username="${salesforce.username}"
password="${salesforce.password}"
securityToken="${salesforce.securityToken}" />
</salesforce:sfdc-config>
<slack:config name="slackConfig">
<slack:slack-auth-connection>
<slack:oauth-authorization-code
consumerKey="${slack.consumerKey}"
consumerSecret="${slack.consumerSecret}" />
<slack:oauth-callback-config
listenerConfig="HTTP_Listener_config"
callbackPath="/slack/callback"
authorizePath="/slack/authorize" />
</slack:slack-auth-connection>
</slack:config>
<http:listener-config name="HTTP_Listener_config">
<http:listener-connection host="0.0.0.0" port="8081" />
</http:listener-config>Generate ALL entries from metadata — the connection provider's , the array, and every entry. For OAuth connectors, requires a attribute referencing an . Missing required childElements = build failure.
childElements[]elementNameattributes[]childElements[]oauth-callback-configlistenerConfighttp:listener-config基于步骤11的元数据,创建配置文件。
src/main/resources/config.yamlyaml
salesforce:
username: "user@example.com"
password: "password"
securityToken: "token"
slack:
consumerKey: "your-consumer-key"
consumerSecret: "your-consumer-secret"配置XML — 结构完全由元数据驱动:
xml
<configuration-properties file="config.yaml" />
<salesforce:sfdc-config name="salesforceConfig">
<salesforce:basic-connection
username="${salesforce.username}"
password="${salesforce.password}"
securityToken="${salesforce.securityToken}" />
</salesforce:sfdc-config>
<slack:config name="slackConfig">
<slack:slack-auth-connection>
<slack:oauth-authorization-code
consumerKey="${slack.consumerKey}"
consumerSecret="${slack.consumerSecret}" />
<slack:oauth-callback-config
listenerConfig="HTTP_Listener_config"
callbackPath="/slack/callback"
authorizePath="/slack/authorize" />
</slack:slack-auth-connection>
</slack:config>
<http:listener-config name="HTTP_Listener_config">
<http:listener-connection host="0.0.0.0" port="8081" />
</http:listener-config>生成元数据中的所有条目——连接提供商的、数组,以及每个条目。对于OAuth连接器,需要引用的属性。缺少所需的childElements会导致构建失败。
childElements[]elementNameattributes[]childElements[]oauth-callback-confighttp:listener-configlistenerConfigStep 13: Get Operation / Source Details
步骤13:获取操作/源详情
For each operation the flow will call, retrieve metadata:
bash
bash scripts/describe_connector.sh sfdc --type operation --name queryResponse shape (same + pattern as ):
attributeschildElementsconfig-detailjson
{
"name": "query",
"prefix": "salesforce",
"elementName": "query",
"attributes": [
{ "attributeName": "config-ref", "required": true },
{ "attributeName": "target" },
{ "attributeName": "targetValue", "defaultValue": "#[payload]", "expressionRequired": true }
],
"childElements": [
{ "paramName": "salesforceQuery", "prefix": "salesforce", "elementName": "salesforce-query", "required": true }
]
}For event-driven triggers (the Step 5 selected trigger is a connector source, not built-in Scheduler or generic HTTP Listener), also retrieve source details:
bash
bash scripts/describe_connector.sh sfdc --type source --name replay-topic-listenerSame + structure. Always include ALL attributes and child elements.
attributeschildElementsrequired: trueThe script also writes (per-op error subset) and the Step 4 invocation populated (connector-wide union). The error types in those files are the ONLY strings allowed in and at Step 14. Do NOT invent identifiers from connector vocabulary — is not real; the actual name is .
tmp/connector-errors/<nick>.<op>.jsontmp/connector-errors/<nick>.jsonNS:ID<on-error-propagate type="..."><on-error-continue type="...">SFTP:FILE_NOT_FOUNDSFTP:FILE_DOESNT_EXIST<raise-error>MULE:*APP:*EC2:*SFTP:*SALESFORCE:*<on-error-*><raise-error type="MULE:RETRY_EXHAUSTED"><raise-error type="EC2:RETRY_EXHAUSTED">Generate operation XML (example):
xml
<salesforce:query config-ref="salesforceConfig">
<salesforce:salesforce-query>
SELECT Id, Name, Amount, StageName
FROM Opportunity
WHERE StageName = 'Closed Won' AND CloseDate = TODAY
</salesforce:salesforce-query>
</salesforce:query>对于流将调用的每个操作,检索元数据:
bash
bash scripts/describe_connector.sh sfdc --type operation --name query响应形状(与的 + 模式相同):
config-detailattributeschildElementsjson
{
"name": "query",
"prefix": "salesforce",
"elementName": "query",
"attributes": [
{ "attributeName": "config-ref", "required": true },
{ "attributeName": "target" },
{ "attributeName": "targetValue", "defaultValue": "#[payload]", "expressionRequired": true }
],
"childElements": [
{ "paramName": "salesforceQuery", "prefix": "salesforce", "elementName": "salesforce-query", "required": true }
]
}对于事件驱动触发器(步骤5选择的触发器是连接器源,而非内置调度器或通用HTTP监听器),还需检索源详情:
bash
bash scripts/describe_connector.sh sfdc --type source --name replay-topic-listener相同的 + 结构。始终包含所有属性和子元素。
attributeschildElementsrequired: true脚本还会将每个操作的错误子集写入,步骤4的调用填充了(连接器范围的并集)。这些文件中的错误类型是步骤14中和允许的唯一字符串。不要从连接器词汇中发明标识符——不是真实的;实际名称是。
tmp/connector-errors/<nick>.<op>.jsontmp/connector-errors/<nick>.json<on-error-propagate type="..."><on-error-continue type="...">NS:IDSFTP:FILE_NOT_FOUNDSFTP:FILE_DOESNT_EXIST<raise-error>MULE:*APP:*EC2:*SFTP:*SALESFORCE:*<on-error-*><raise-error type="MULE:RETRY_EXHAUSTED"><raise-error type="EC2:RETRY_EXHAUSTED">生成操作XML(示例):
xml
<salesforce:query config-ref="salesforceConfig">
<salesforce:salesforce-query>
SELECT Id, Name, Amount, StageName
FROM Opportunity
WHERE StageName = 'Closed Won' AND CloseDate = TODAY
</salesforce:salesforce-query>
</salesforce:query>Step 14: Generate Complete Flow
步骤14:生成完整流
Generate the complete flow in using metadata from Steps 10, 12. Do NOT use hardcoded structures.
src/main/mule/<project-name>.xmlxml
<?xml version="1.0" encoding="UTF-8"?>
<mule xmlns="http://www.mulesoft.org/schema/mule/core"
xmlns:salesforce="http://www.mulesoft.org/schema/mule/salesforce"
xmlns:ee="http://www.mulesoft.org/schema/mule/ee/core"
xmlns:doc="http://www.mulesoft.org/schema/mule/documentation"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.mulesoft.org/schema/mule/core http://www.mulesoft.org/schema/mule/core/current/mule.xsd
http://www.mulesoft.org/schema/mule/salesforce http://www.mulesoft.org/schema/mule/salesforce/current/mule-salesforce.xsd
http://www.mulesoft.org/schema/mule/ee/core http://www.mulesoft.org/schema/mule/ee/core/current/mule-ee.xsd">
<!-- One namespace URI + XSD URL pair per <dependency> in pom.xml. Do not include doc or xsi. -->
<configuration-properties file="config.yaml" />
<salesforce:sfdc-config name="salesforceConfig">
<salesforce:basic-connection
username="${salesforce.username}"
password="${salesforce.password}"
securityToken="${salesforce.securityToken}" />
</salesforce:sfdc-config>
<flow name="integration-flow">
<scheduler>
<scheduling-strategy>
<fixed-frequency frequency="300000"/>
</scheduling-strategy>
</scheduler>
<salesforce:query config-ref="salesforceConfig">
<salesforce:salesforce-query>
SELECT Id, Name, Amount FROM Opportunity WHERE StageName = 'Closed Won'
</salesforce:salesforce-query>
</salesforce:query>
<ee:transform>
<ee:message>
<ee:set-payload><![CDATA[%dw 2.0
output application/json
---
payload]]></ee:set-payload>
</ee:message>
</ee:transform>
</flow>
</mule>xsi:schemaLocationInclude in exactly one entry for each module or connector namespace that has a matching in (core, ee/core, and each connector — , , , , etc.). Each entry is the namespace URI followed by the URL of its XSD, separated by whitespace.
xsi:schemaLocation<dependency>pom.xmlhttpsalesforcedbanypoint-mqNamespaces that must NOT appear in (closed list):
xsi:schemaLocation| Namespace | | Why it's excluded from |
|---|---|---|
| Required when any | No XSD exists at that URL. |
| Required to use the | |
Namespace ↔ dependency parity: if a namespace is declared via but has no matching in , the correct fix is to add the dependency or remove the namespace — not to add a schemaLocation entry that points at a non-existent XSD. Same failure mode as above, different root cause; applies to , , , when those namespaces are declared without their connector dep.
xmlns:X<dependency>pom.xmlmule-documentation.xsdmule-scriptingmule-objectstoremule-validationmule-httpGeneration rules:
- Use exact from metadata for all tags
elementName - Use exact from metadata for all attributes
attributeName - Include every attribute and child element
required: true - Use the correct namespace prefix from metadata
- Reference names from Step 12
config-ref - Generate child elements in the exact order of the array — XSD schemas enforce strict sequencing
childElements[] - Do not add wrapper elements that are not in metadata (e.g., use not
<reconnect>)<reconnection-strategy><reconnect> - Place reconnection at the config connection level, not operation level (unless metadata explicitly includes it there)
- Build from the module/connector
xsi:schemaLocationlist in<dependency>; never includepom.xmlordoc. See the rule block above.xsi
使用步骤10、12的元数据,在中生成完整流。不要使用硬编码结构。
src/main/mule/<project-name>.xmlxml
<?xml version="1.0" encoding="UTF-8"?>
<mule xmlns="http://www.mulesoft.org/schema/mule/core"
xmlns:salesforce="http://www.mulesoft.org/schema/mule/salesforce"
xmlns:ee="http://www.mulesoft.org/schema/mule/ee/core"
xmlns:doc="http://www.mulesoft.org/schema/mule/documentation"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.mulesoft.org/schema/mule/core http://www.mulesoft.org/schema/mule/core/current/mule.xsd
http://www.mulesoft.org/schema/mule/salesforce http://www.mulesoft.org/schema/mule/salesforce/current/mule-salesforce.xsd
http://www.mulesoft.org/schema/mule/ee/core http://www.mulesoft.org/schema/mule/ee/core/current/mule-ee.xsd">
<!-- 每个pom.xml中的<dependency>对应一个命名空间URI + XSD URL对。不要包含doc或xsi。 -->
<configuration-properties file="config.yaml" />
<salesforce:sfdc-config name="salesforceConfig">
<salesforce:basic-connection
username="${salesforce.username}"
password="${salesforce.password}"
securityToken="${salesforce.securityToken}" />
</salesforce:sfdc-config>
<flow name="integration-flow">
<scheduler>
<scheduling-strategy>
<fixed-frequency frequency="300000"/>
</scheduling-strategy>
</scheduler>
<salesforce:query config-ref="salesforceConfig">
<salesforce:salesforce-query>
SELECT Id, Name, Amount FROM Opportunity WHERE StageName = 'Closed Won'
</salesforce:salesforce-query>
</salesforce:query>
<ee:transform>
<ee:message>
<ee:set-payload><![CDATA[%dw 2.0
output application/json
---
payload]]></ee:set-payload>
</ee:message>
</ee:transform>
</flow>
</mule>xsi:schemaLocation在中为每个在中有匹配的模块或连接器命名空间(core、ee/core以及每个连接器——、、、等)添加恰好一个条目。每个条目是命名空间URI后跟其XSD的URL,用空格分隔。
xsi:schemaLocationpom.xml<dependency>httpsalesforcedbanypoint-mq不得出现在中的命名空间(封闭列表):
xsi:schemaLocation| 命名空间 | | 为什么从 |
|---|---|---|
| 当使用任何 | 该URL不存在XSD。 |
| 使用 | |
命名空间与依赖项一致性: 如果通过声明了命名空间,但中没有匹配的,正确的修复是添加依赖项或移除命名空间——而非添加指向不存在XSD的schemaLocation条目。与上面的失败模式相同,但根本原因不同;适用于、、、等命名空间被声明但没有其连接器依赖项的情况。
xmlns:Xpom.xml<dependency>mule-documentation.xsdmule-scriptingmule-objectstoremule-validationmule-http生成规则:
- 对所有标签使用元数据中的精确
elementName - 对所有属性使用元数据中的精确
attributeName - 包含每个属性和子元素
required: true - 使用元数据中的正确命名空间前缀
- 引用步骤12中的名称
config-ref - 按数组的精确顺序生成子元素——XSD模式强制严格排序
childElements[] - 不要添加元数据中没有的包装元素(例如,使用而非
<reconnect>)<reconnection-strategy><reconnect> - 将重新连接放在配置连接级别,而非操作级别(除非元数据明确包含在操作级别)
- 从中的模块/连接器
pom.xml列表构建<dependency>;永远不要包含xsi:schemaLocation或doc。请参阅上面的规则块。xsi
Step 15: Add doc:name
and doc:description
to Canvas-Visible Elements
doc:namedoc:description步骤15:为画布可见元素添加doc:name
和doc:description
doc:namedoc:descriptionEvery XML element that appears as a visible node on the flow canvas MUST have and attributes. is displayed as the label text on the canvas node (overriding when present), so keep it concise and meaningful.
doc:namedoc:descriptiondoc:descriptiondoc:namePrerequisite — namespace declaration:
Any use of a attribute requires on the root (see Step 14). If it is missing, every triggers . The fix is to add the attribute — and, per Step 14's construction rule, not to add to .
doc:*xmlns:doc="http://www.mulesoft.org/schema/mule/documentation"<mule>doc:nameThe prefix "doc" for attribute "doc:name" associated with an element type "..." is not boundxmlns:docxsi:schemaLocationmule-documentationxsi:schemaLocationInfer descriptions from the field returned by , , and metadata, the XML structure and element purpose, flow comments, and the overall integration context.
descriptionconfig-detailoperation-detailsource-detailRules:
- Human-readable sentences that explain the element's purpose in this integration, not generic documentation
- Max 125 characters — keeps labels readable on the canvas
- Active voice; be specific about what the element does
- Include relevant details: endpoints, object types, field names, scheduling intervals
- Add as a short label alongside
doc:namedoc:description
Add and to these canvas-visible element types:
doc:namedoc:description| Element Type | Examples |
|---|---|
| Flows/sub-flows | |
| Sources/triggers | |
| Operations/processors | |
| Scopes/containers | |
| Branches/routes | |
| Global configs | |
Do NOT add to inner property elements — these aren't rendered on the canvas:
doc:description- ,
<scheduling-strategy>,<fixed-frequency><cron> - ,
<http:body>,<http:headers><http:query-params> - ,
<reconnection><reconnect> - ,
<non-repeatable-stream><repeatable-in-memory-stream> - Operation-specific child content elements (e.g., ,
<salesforce:salesforce-query>)<slack:chatpost-message-content> - Transform inner elements (,
<ee:message>,<ee:set-payload>,<ee:variables>)<ee:set-variable>
Example — after (with doc:name and doc:description):
xml
<flow name="contact-sync-flow"
doc:name="Contact Sync Flow"
doc:description="Receives HTTP requests and syncs modified Salesforce contacts to Slack">
<http:listener config-ref="httpConfig" path="/contacts" allowedMethods="GET"
doc:name="HTTP GET /contacts"
doc:description="Receives incoming HTTP GET requests on the /contacts endpoint" />
<salesforce:query config-ref="salesforceConfig"
doc:name="Query modified contacts"
doc:description="Queries Salesforce for Contact records modified since the last sync">
<salesforce:salesforce-query>
SELECT Id, Name, Email FROM Contact WHERE LastModifiedDate > :lastSync
</salesforce:salesforce-query>
</salesforce:query>
<choice
doc:name="Contacts found?"
doc:description="Routes processing based on whether any modified contacts were returned">
<when expression="#[sizeOf(payload) > 0]"
doc:name="Has contacts"
doc:description="Processes each contact when results are not empty">
<foreach
doc:name="For each contact"
doc:description="Iterates through each modified contact to send to Slack">
<ee:transform
doc:name="Map to JSON"
doc:description="Transforms Salesforce Contact into a simplified JSON structure with id, name, and email">
<ee:message>
<ee:set-payload><![CDATA[%dw 2.0
output application/json
---
payload map { id: $.Id, name: $.Name, email: $.Email }]]></ee:set-payload>
</ee:message>
</ee:transform>
<slack:create-chatpost-message config-ref="slackConfig"
doc:name="Post to Slack"
doc:description="Sends the transformed contact data as a message to the configured Slack channel">
<slack:chatpost-message-content>#[payload]</slack:chatpost-message-content>
</slack:create-chatpost-message>
</foreach>
</when>
<otherwise
doc:name="No contacts"
doc:description="Handles the case when no modified contacts are found">
<logger level="INFO" message="No contacts found"
doc:name="Log no contacts"
doc:description="Logs that no modified contacts were found in this request" />
</otherwise>
</choice>
</flow>流画布上显示为可见节点的每个XML元素必须有和属性。显示为画布节点的标签文本(存在时覆盖),因此保持简洁且有意义。
doc:namedoc:descriptiondoc:descriptiondoc:name前提条件 — 命名空间声明:
任何属性的使用都需要在根元素上添加(请参阅步骤14)。如果缺失,每个都会触发错误:。修复方法是添加属性——并且根据步骤14的构建规则,不要将添加到。
doc:*<mule>xmlns:doc="http://www.mulesoft.org/schema/mule/documentation"doc:nameThe prefix "doc" for attribute "doc:name" associated with an element type "..." is not boundxmlns:docxsi:schemaLocationmule-documentationxsi:schemaLocation从、和元数据返回的字段、XML结构和元素用途、流注释以及整体集成上下文推断描述。
config-detailoperation-detailsource-detaildescription规则:
- 人类可读的句子,解释元素在此集成中的用途,而非通用文档
- 最多125个字符——保持标签在画布上可读
- 主动语态;具体说明元素的作用
- 包含相关细节:端点、对象类型、字段名称、调度间隔
- 同时添加作为短标签和
doc:namedoc:description
为以下画布可见元素类型添加和:
doc:namedoc:description| 元素类型 | 示例 |
|---|---|
| 流/子流 | |
| 源/触发器 | |
| 操作/处理器 | |
| 作用域/容器 | |
| 分支/路由 | |
| 全局配置 | |
不要为内部属性元素添加——这些不会在画布上呈现:
doc:description- 、
<scheduling-strategy>、<fixed-frequency><cron> - 、
<http:body>、<http:headers><http:query-params> - 、
<reconnection><reconnect> - 、
<non-repeatable-stream><repeatable-in-memory-stream> - 操作特定的子内容元素(例如、
<salesforce:salesforce-query>)<slack:chatpost-message-content> - 转换内部元素(、
<ee:message>、<ee:set-payload>、<ee:variables>)<ee:set-variable>
示例 — 添加后(带doc:name和doc:description):
xml
<flow name="contact-sync-flow"
doc:name="Contact Sync Flow"
doc:description="Receives HTTP requests and syncs modified Salesforce contacts to Slack">
<http:listener config-ref="httpConfig" path="/contacts" allowedMethods="GET"
doc:name="HTTP GET /contacts"
doc:description="Receives incoming HTTP GET requests on the /contacts endpoint" />
<salesforce:query config-ref="salesforceConfig"
doc:name="Query modified contacts"
doc:description="Queries Salesforce for Contact records modified since the last sync">
<salesforce:salesforce-query>
SELECT Id, Name, Email FROM Contact WHERE LastModifiedDate > :lastSync
</salesforce:salesforce-query>
</salesforce:query>
<choice
doc:name="Contacts found?"
doc:description="Routes processing based on whether any modified contacts were returned">
<when expression="#[sizeOf(payload) > 0]"
doc:name="Has contacts"
doc:description="Processes each contact when results are not empty">
<foreach
doc:name="For each contact"
doc:description="Iterates through each modified contact to send to Slack">
<ee:transform
doc:name="Map to JSON"
doc:description="Transforms Salesforce Contact into a simplified JSON structure with id, name, and email">
<ee:message>
<ee:set-payload><![CDATA[%dw 2.0
output application/json
---
payload map { id: $.Id, name: $.Name, email: $.Email }]]></ee:set-payload>
</ee:message>
</ee:transform>
<slack:create-chatpost-message config-ref="slackConfig"
doc:name="Post to Slack"
doc:description="Sends the transformed contact data as a message to the configured Slack channel">
<slack:chatpost-message-content>#[payload]</slack:chatpost-message-content>
</slack:create-chatpost-message>
</foreach>
</when>
<otherwise
doc:name="No contacts"
doc:description="Handles the case when no modified contacts are found">
<logger level="INFO" message="No contacts found"
doc:name="Log no contacts"
doc:description="Logs that no modified contacts were found in this request" />
</otherwise>
</choice>
</flow>Step 16: Build and Verify
步骤16:构建与验证
Pre-build validation
预构建验证
As the FIRST tool call of the build response, run:
bash
bash <skill-dir>/scripts/validate_before_build.sh ./<project-name>The validator runs three static checks (error-type whitelist, namespace↔dependency parity, canonical XSD URL shape) and exits 1 on any violation. If it fails, fix the reported issue (revisit Step 14), re-run the validator, and only proceed to after it exits 0. This preserves the one-command-per-response discipline — validator and mvn stay in separate responses.
mvn clean packagebash
cd <project-name>
mvn clean packageSuccess: .
target/<project-name>-1.0.0-SNAPSHOT-mule-application.jarBuild-then-verify protocol (do NOT skip steps):
- Emit as the only tool call in this response. Do not include a completion signal, a follow-up
mvn clean package, or any other tool call alongside it. Stop and wait for the build output.ls - You MUST wait until the mvn clean package succeeds. Do NOT make any assumptions about build completion. The terminal output is the ONLY source of truth.
- Read the output:
- If the last line block contains , proceed to Step 17 (cleanup) in a new response.
BUILD SUCCESS - If the last line block contains , find the
BUILD FAILUREline beginning[ERROR], diagnose the root cause, edit the offending file (revisiting the relevant earlier Step — e.g. Step 14 for XML structure, Step 15 for documentation attributes and namespaces), and return to step 1 of this protocol. MUST follow the "Best Practices" section for diagnosing the issue and applying the correct fix. Never assume a solution. ALWAYS reference the connector metadata sources and operations under tmp/ folder as your source of truth.Failed to execute goal ...
- If the last line block contains
After any or on , on flow XML, or on config XML, you MUST re-run before declaring completion. Editing without re-verifying silently ships a broken build.
<write_to_file><replace_in_file>pom.xmlmvn clean package作为构建响应的第一个工具调用,运行:
bash
bash <skill-dir>/scripts/validate_before_build.sh ./<project-name>验证器运行三个静态检查(错误类型白名单、命名空间与依赖项一致性、规范XSD URL形状),任何违规时返回退出码1。如果失败,修复报告的问题(重新访问步骤14),重新运行验证器,仅在返回退出码0后才继续。这保持了每个响应一个命令的规范——验证器和mvn保持在不同的响应中。
mvn clean packagebash
cd <project-name>
mvn clean package成功:。
target/<project-name>-1.0.0-SNAPSHOT-mule-application.jar构建后验证协议(不要跳过步骤):
- 将作为此响应中的唯一工具调用。不要包含完成信号、后续
mvn clean package或任何其他工具调用。停止并等待构建输出。ls - 必须等待成功。不要对构建完成做出任何假设。终端输出是唯一的真相来源。
mvn clean package - 读取输出:
- 如果最后一行块包含,在新响应中继续步骤17(清理)。
BUILD SUCCESS - 如果最后一行块包含,找到以
BUILD FAILURE开头的行[ERROR],诊断根本原因,编辑有问题的文件(重新访问相关的早期步骤——例如步骤14处理XML结构,步骤15处理文档属性和命名空间),然后返回此协议的步骤1。必须遵循“最佳实践”部分诊断问题并应用正确的修复。永远不要假设解决方案。始终参考tmp/文件夹下的连接器元数据来源和操作作为真相来源。Failed to execute goal ...
- 如果最后一行块包含
在对、流XML或配置XML进行任何或后,必须重新运行才能宣布完成。 编辑后不重新验证会静默发布损坏的构建。
pom.xml<write_to_file><replace_in_file>mvn clean packageStep 17: Clean Up Workspace tmp/
tmp/步骤17:清理工作区tmp/
tmp/Pre-condition: The immediately preceding response must be a build response (per Step 16) whose returned output contains . If this is not true, do NOT enter Step 17 — go back to Step 16.
BUILD SUCCESSThe workspace-relative directory carries Phase 1 → Phase 2 coordination state — , , , , , plus the scratch files written by and . Once the build passes those files have served their purpose — they exist only so steps can hand state to each other, not as artifacts the user needs.
tmp/tmp/mule-dev-env.jsontmp/connector-choices/tmp/connector-versions/tmp/connector-metadata/tmp/connector-errors/tmp/mule-dev-*-XXXXXXget_latest_connector.shdescribe_connector.shRemove the directory in its own response, as the only tool call:
bash
rm -r tmp/Discipline:
- Delete only at the workspace root.
tmp/
前置条件: 紧接的前一个响应必须是构建响应(根据步骤16),其返回的输出包含。如果不满足,不要进入步骤17——返回步骤16。无论最终尝试成功或失败,都必须清理tmp/文件夹。
BUILD SUCCESS工作区相对的目录承载第一阶段→第二阶段的协调状态——、、、、,以及和写入的临时文件。一旦构建通过,这些文件就完成了它们的用途——它们仅用于步骤之间传递状态,而非用户需要的工件。
tmp/tmp/mule-dev-env.jsontmp/connector-choices/tmp/connector-versions/tmp/connector-metadata/tmp/connector-errors/get_latest_connector.shdescribe_connector.shtmp/mule-dev-*-XXXXXX在单独的响应中删除该目录,作为唯一的工具调用:
bash
rm -r tmp/规范:
- 仅删除工作区根目录下的。
tmp/
Step 18: Declare Completion
步骤18:宣布完成
Pre-condition: The two preceding responses must be (a) a build response (per Step 16) returning , immediately followed by (b) a cleanup response (per Step 17) that ran . If either is missing, do NOT enter Step 18 — go back to whichever step is missing. You HAVE to clean up the tmp/ folder no matter the attemps succeed or fail at the end.
BUILD SUCCESSrm -r tmp/Discipline:
- The completion signal is the ONLY tool call in this response. Do not run here. Do not add follow-up shell commands. The build was already executed and verified in the previous response.
mvn - Do not declare completion after a , even if you believe the subsequent edit fixes it. Re-run
BUILD FAILUREin its own response (Step 16), observemvn clean package, then declare completion in the next response.BUILD SUCCESS - Do not declare completion if the most recent build was never actually executed (e.g., the command was shown but no result came back). Re-run it in its own response and wait.
Completion message content — keep it tight. The user can see the files and the build log. The completion message is evidence that the build passed, not a marketing document. Include exactly these, and nothing else:
- The successful build artifact path:
target/<project-name>-1.0.0-SNAPSHOT-mule-application.jar - One sentence naming the integration (what it does, e.g. "Polls S3 every 5s and publishes new-object events to a JMS queue").
- The keys the user still needs to fill in (credentials, bucket names, queue names) — as a short bullet list. This is the only information that is not already visible on disk.
config.yaml
Do not include: lengthy "Features Implemented" sections, redacted JSON payload examples, "Next Steps" (the user will deploy when they're ready), or recap tables.
前置条件: 前两个响应必须是(a)构建响应(根据步骤16)返回,紧接着是(b)清理响应(根据步骤17)运行。如果任何一个缺失,不要进入步骤18——返回缺失的步骤。无论最终尝试成功或失败,都必须清理tmp/文件夹。
BUILD SUCCESSrm -r tmp/规范:
- 完成信号是此响应中的唯一工具调用。不要在此处运行。不要添加后续shell命令。构建已在前一个响应中执行并验证。
mvn - 不要在后宣布完成,即使您认为后续编辑修复了问题。在单独的响应中重新运行
BUILD FAILURE(步骤16),观察mvn clean package,然后在下一个响应中宣布完成。BUILD SUCCESS - 如果最近的构建从未实际执行(例如命令已显示但未返回结果),不要宣布完成。在单独的响应中重新运行并等待。
完成消息内容 — 保持简洁。用户可以看到文件和构建日志。完成消息是构建成功的证据,而非营销文档。仅包含以下内容,不要添加其他:
- 成功构建的工件路径:
target/<project-name>-1.0.0-SNAPSHOT-mule-application.jar - 一句话命名集成(它做什么,例如“每5秒轮询S3并将新对象事件发布到JMS队列”)。
- 用户仍需填写的键(凭证、存储桶名称、队列名称)——作为简短的项目符号列表。这是磁盘上未显示的唯一信息。
config.yaml
不要包含:冗长的“已实现功能”部分、编辑后的JSON负载示例、“下一步”(用户准备好后会部署)或回顾表格。
Best Practices
最佳实践
1. Dynamic connector versions. See Step 3's "Version source-of-truth rule" for the full mandate.
- ✅ Phase 1: → list →
get_latest_connector.sh mule-salesforce-connector sfdc→ draft atpick_connector.sh sfdc <gav>tmp/connector-choices/sfdc.json - ✅ Phase 2: (first action of Step 8) →
commit_connectors.shfor thebuild_deps.shstring, ordx mule project create --dependenciesfor a single GAV elsewherebuild_gav.sh tmp/connector-versions/<name>.json - ❌ Hardcoded literal:
com.mulesoft.connectors:mule-salesforce-connector:10.20.0 - ❌ Pasted from (snapshot only — drifts)
references/connector-catalog.md - ❌ Search term alone as the GAV:
salesforce
2. Metadata-driven XML generation. Never manually write XML. Always use metadata from , , :
operation-detailconfig-detailsource-detail- → XML attributes on the tag (use
attributesverbatim)attributeName - → nested XML elements (use
childElementsas the tag)prefix:elementName - Always include every attribute and child element
required: true - Optional entries may be omitted unless specifically needed
- → understand what the parameter does
description - → constrain values
allowedValues - → skip if acceptable
defaultValue
3. System-specific connectors first, every time. Always search Exchange for a dedicated connector before falling back to HTTP — and "before" means literally before, not "before I type my decision". The skill's discipline is that a Phase-1 draft in (or the post-commit pin in ) is the only evidence that allows declaring "system X is covered"; the helper script having exited 1 is the only evidence that allows declaring "no dedicated connector, falling back to HTTP".
tmp/connector-choices/tmp/connector-versions/4. Validate metadata before generation. Use for features, / / for exact specs.
describe-connectorconfig-detailoperation-detailsource-detail1. 动态连接器版本。请参阅步骤3的“版本来源规则”获取完整要求。
- ✅ 第一阶段:→ 列出 →
get_latest_connector.sh mule-salesforce-connector sfdc→ 草稿存储在pick_connector.sh sfdc <gav>tmp/connector-choices/sfdc.json - ✅ 第二阶段:(步骤8的第一个操作) →
commit_connectors.sh生成build_deps.sh字符串,或dx mule project create --dependencies获取第二阶段其他地方的单个GAVbuild_gav.sh tmp/connector-versions/<name>.json - ❌ 硬编码文字版本:
com.mulesoft.connectors:mule-salesforce-connector:10.20.0 - ❌ 从粘贴(仅快照——会随时间变化)
references/connector-catalog.md - ❌ 仅用搜索词作为GAV:
salesforce
2. 元数据驱动的XML生成。永远不要手动编写XML。始终使用、、的元数据:
operation-detailconfig-detailsource-detail- → 标签上的XML属性(按原样使用
attributes)attributeName - → 嵌套XML元素(使用
childElements作为标签)prefix:elementName - 始终包含每个属性和子元素
required: true - 可选条目除非特别需要,否则可以省略
- → 理解参数的作用
description - → 约束值
allowedValues - → 如果可接受则跳过
defaultValue
3. 优先使用系统特定连接器,每次都如此。在回退到HTTP之前,始终先在Exchange中搜索专用连接器——“之前”指字面上的之前,而非“在我输入决策之前”。技能的规范是:中的第一阶段草稿(或提交后的固定项在)是宣布“系统X已覆盖”的唯一证据;辅助脚本返回退出码1是宣布“无专用连接器,回退到HTTP”的唯一证据。
tmp/connector-choices/tmp/connector-versions/4. 生成前验证元数据。使用获取功能,使用//获取精确规格。
describe-connectorconfig-detailoperation-detailsource-detailCommon Integration Patterns
常见集成模式
#1 HTTP API → Query → Response: http:listener → salesforce:query → ee:transform → response (Components: HTTP + Salesforce/Database)
#2 Scheduled Sync → Query → Transform → Notification: scheduler → salesforce:query → ee:transform → slack:post-message (Components: Scheduler + Salesforce + Slack)
#3 Scheduled Sync → Query → Transform → Batch Insert: scheduler → query → ee:transform → foreach → db:insert (Components: Scheduler + Source System + Database)
#4 Event listener → Transform → Downstream system: → ee:transform → target-connector operation (Components: Source System with native listener + Target System). This pattern shines when the source connector exposes a real event source in — use that instead of polling via Scheduler.
<connector>:<event-source>sources[]#1 HTTP API → 查询 → 响应: http:listener → salesforce:query → ee:transform → response(组件:HTTP + Salesforce/Database)
#2 调度同步 → 查询 → 转换 → 通知: scheduler → salesforce:query → ee:transform → slack:post-message(组件:调度器 + Salesforce + Slack)
#3 调度同步 → 查询 → 转换 → 批量插入: scheduler → query → ee:transform → foreach → db:insert(组件:调度器 + 源系统 + Database)
#4 事件监听器 → 转换 → 下游系统: → ee:transform → 目标连接器操作(组件:带有原生监听器的源系统 + 目标系统)。当源连接器在中暴露真实事件源时,此模式效果最佳——使用它而非通过调度器轮询。
<connector>:<event-source>sources[]Troubleshooting
故障排除
JAVA_HOME not set:
export JAVA_HOME=$(/usr/libexec/java_home -v 11)anypoint-cli-v4 not found:
npm install -g @mulesoft/anypoint-cli-v4DX plugin not found:
npm install -g @salesforce/anypoint-cli-dx-mule-pluginConnector not found: check spelling · try and · verify Mule 4 compatibility.
mule-<name>-connectormule4-<name>-connectorWrong connector selected: use specific search terms (, not ). scores by token overlap and requires at least one token match — a bogus search will exit 1 rather than return a random result.
mule-http-connectorhttpscripts/get_latest_connector.shRuntime path required: first use of or related commands prompts for runtime location. The path is saved to .
dx mule describe-connector~/.mule-dx/config.jsonDatabase driver missing: if Step 6b didn't record , return to Step 6b to make the choice (with prompts where the provider is //). If the sidecar exists but is missing the entries, return to Step 9 — it reads that file and applies every entry as a + pair. Do not invent a driver GAV at Step 9.
tmp/connector-choices/db-driver.jsongenericdata-sourcederbypom.xml<dependency><sharedLibrary>The mule application does not contain the following shared libraries: [<artifactId>:<groupId>]<dependency><sharedLibrary>mule-maven-plugingroupIdartifactIdDerby driver layout: see . Derby 10.15+ split into multiple artifacts ( + + for embedded; + for network client), so the list has multiple entries, not one.
references/jdbc-drivers.mdderbyderbysharedderbytoolsderbyclientderbyshared<sharedLibrary>JAVA_HOME未设置:
export JAVA_HOME=$(/usr/libexec/java_home -v 11)anypoint-cli-v4未找到:
npm install -g @mulesoft/anypoint-cli-v4DX插件未找到:
npm install -g @salesforce/anypoint-cli-dx-mule-plugin连接器未找到: 检查拼写 · 尝试和 · 验证Mule 4兼容性。
mule-<name>-connectormule4-<name>-connector选择了错误的连接器: 使用特定搜索词(,而非)。按标记重叠评分,需要至少一个标记匹配——虚假搜索会返回退出码1,而非随机结果。
mule-http-connectorhttpscripts/get_latest_connector.sh需要运行时路径: 首次使用或相关命令时,会提示输入运行时位置。路径会保存到。
dx mule describe-connector~/.mule-dx/config.jsonDatabase驱动缺失: 如果步骤6b未记录,返回步骤6b做出选择(提供商为//时提示)。如果辅助文件存在但缺失条目,返回步骤9——它读取该文件并将每个条目应用为 + 对。不要在步骤9中发明驱动GAV。
tmp/connector-choices/db-driver.jsongenericdata-sourcederbypom.xml<dependency><sharedLibrary>The mule application does not contain the following shared libraries: [<artifactId>:<groupId>]<dependency>mule-maven-plugin<sharedLibrary>groupIdartifactIdDerby驱动布局: 请参阅。Derby 10.15+拆分为多个工件(嵌入式为 + + ;网络客户端为 + ),因此列表有多个条目,而非一个。
references/jdbc-drivers.mdderbyderbysharedderbytoolsderbyclientderbyshared<sharedLibrary>Quick Reference
快速参考
<skill-dir>../scripts/...bash
undefined下面的是“技能已激活”消息中提供的绝对路径。请一致使用——不要构造相对路径。
<skill-dir>../scripts/...bash
undefinedStep 1: validate toolchain (CLI, DX plugin, Java 11+, Mule runtime presence) - Validation-only
步骤1:验证工具链(CLI、DX插件、Java 11+、Mule运行时是否存在) - 仅用于验证
bash <skill-dir>/scripts/validate_prerequisites.sh
bash <skill-dir>/scripts/validate_prerequisites.sh
Step 3: connector search — list, decide, draft (one loop per system; search
步骤3:连接器搜索 — 列出、决策、记录草稿(每个系统循环一次;搜索
EVERY named system including mid-market SaaS; don't pre-judge as "no connector")
每个命名系统,包括中型SaaS;不要预先判断“无连接器”)
bash <skill-dir>/scripts/get_latest_connector.sh <search-term> [<nickname>] # prints ranked GAVs to stdout
bash <skill-dir>/scripts/get_latest_connector.sh <search-term> [<nickname>] # 将排名GAV输出到stdout
... agent reads list, decides (or AskUserQuestion for real variant ambiguity), then:
... 代理读取列表,决策(或针对真实变体模糊性使用AskUserQuestion),然后:
bash <skill-dir>/scripts/pick_connector.sh <nickname> groupId:assetId:version # drafts to tmp/connector-choices/
bash <skill-dir>/scripts/pick_connector.sh <nickname> groupId:assetId:version # 草稿存储到tmp/connector-choices/
Step 4: describe connectors (Phase 1 — wrapper saves JSON + echoes sources[] digest)
步骤4:描述连接器(第一阶段 — 包装脚本保存JSON + 输出sources[]摘要)
bash <skill-dir>/scripts/describe_connector.sh <nickname> # one per connector
bash <skill-dir>/scripts/describe_connector.sh <nickname> # 每个连接器调用一次
Step 6: connection-provider detail (Phase 1 — also cached for Phase 2).
步骤6:连接提供商详情(第一阶段 — 也缓存供第二阶段使用)。
Flag semantics: --name = connection provider, --config-name = config name.
标志语义:--name = 连接提供商,--config-name = 配置名称。
GAV_A="$(bash <skill-dir>/scripts/build_gav.sh tmp/connector-choices/a.json)"
NODE_NO_WARNINGS=1 anypoint-cli-v4 dx mule describe-connector --connector "$GAV_A"
--type connection-provider --name <prov> --config-name <name> --output json \
--type connection-provider --name <prov> --config-name <name> --output json \
tmp/connector-metadata/a-config.json
GAV_A="$(bash <skill-dir>/scripts/build_gav.sh tmp/connector-choices/a.json)"
NODE_NO_WARNINGS=1 anypoint-cli-v4 dx mule describe-connector --connector "$GAV_A"
--type connection-provider --name <prov> --config-name <name> --output json \
--type connection-provider --name <prov> --config-name <name> --output json \
tmp/connector-metadata/a-config.json
Step 8: promote drafts to pinned versions, then create the real project (Phase 2)
步骤8:将草稿升级为固定版本,然后创建真实项目(第二阶段)
bash <skill-dir>/scripts/commit_connectors.sh # tmp/connector-choices/ → tmp/connector-versions/
MULE_VERSION=$(jq -r '.mule_version' tmp/mule-dev-env.json)
NODE_NO_WARNINGS=1 anypoint-cli-v4 dx mule project create <name>
--group-id com.example
--mule-version "$MULE_VERSION"
--dependencies "$(bash <skill-dir>/scripts/build_deps.sh)" # reads every tmp/connector-versions/*.json pin
--group-id com.example
--mule-version "$MULE_VERSION"
--dependencies "$(bash <skill-dir>/scripts/build_deps.sh)" # reads every tmp/connector-versions/*.json pin
bash <skill-dir>/scripts/commit_connectors.sh # tmp/connector-choices/ → tmp/connector-versions/
MULE_VERSION=$(jq -r '.mule_version' tmp/mule-dev-env.json)
NODE_NO_WARNINGS=1 anypoint-cli-v4 dx mule project create <name>
--group-id com.example
--mule-version "$MULE_VERSION"
--dependencies "$(bash <skill-dir>/scripts/build_deps.sh)" # 读取每个tmp/connector-versions/*.json固定项
--group-id com.example
--mule-version "$MULE_VERSION"
--dependencies "$(bash <skill-dir>/scripts/build_deps.sh)" # 读取每个tmp/connector-versions/*.json固定项
Step 10: OAuth → HTTP defensive check (only when Step 6 chose OAuth/JWT/auth-code
步骤10:OAuth → HTTP防御性检查(仅当步骤6选择了OAuth/JWT/auth-code
or the trigger is HTTP Listener)
或触发器是HTTP监听器时)
bash <skill-dir>/scripts/maybe_add_http_connector.sh --project ./<name> "<provider1>" "<provider2>"
bash <skill-dir>/scripts/maybe_add_http_connector.sh --project ./<name> "<provider1>" "<provider2>"
Step 13: operation / source details (Phase 2 — wrapper saves JSON + caches errorTypes)
步骤13:操作/源详情(第二阶段 — 包装脚本保存JSON + 缓存errorTypes)
bash <skill-dir>/scripts/describe_connector.sh <nickname> --type operation --name <op>
bash <skill-dir>/scripts/describe_connector.sh <nickname> --type source --name <src>
bash <skill-dir>/scripts/describe_connector.sh <nickname> --type operation --name <op>
bash <skill-dir>/scripts/describe_connector.sh <nickname> --type source --name <src>
Step 16: pre-mvn validation — error-type whitelist + namespace↔dep parity + XSD shape
步骤16:预mvn验证 — 错误类型白名单 + 命名空间与依赖项一致性 + XSD形状
bash <skill-dir>/scripts/validate_before_build.sh ./<project>
| Pre-mvn validation | `bash <skill-dir>/scripts/validate_before_build.sh ./<project>` |
---bash <skill-dir>/scripts/validate_before_build.sh ./<project>
| 预mvn验证 | `bash <skill-dir>/scripts/validate_before_build.sh ./<project>` |
---