Batch Workflows Fan-out Skill
Purpose
Provide the internal fan-out engine used by the product-facing Batch Jira
Workflows and Batch GitHub Workflows presets. Each provider-specific preset owns
its fixed source model and curated destination list; this shared skill handles
queueing, runtime inheritance, publishing, idempotency, and evidence. Every child inherits the parent runtime
(runtimeInheritance="caller") and a single shared publish policy. The parent
records a summary artifact that links every queued child workflow.
This parent batch skill does not publish repository changes itself. It records
child workflow queueing evidence in artifacts/batch-workflows-result.json;
each queued child workflow owns its configured publish outcome.
This replaces one-off prompts like "Queue Jira Verify for every MM issue in In Progress" with a single batch run.
Inputs (preset inputs / skill args)
jira_project_key(string, required): Jira project key, for exampleMM.jira_status(string, required): Jira status name, for exampleIn Progress.run_ref(string, required): child capability to run per target. Defaultskill:jira-verify. The Jira preset supportsskill:jira-verify,preset:jira-implement, andpreset:jira-orchestrate. The separate GitHub preset supportspreset:github-issue-implementandpreset:github-issue-orchestratethrough the same helper.max_workflows(number, optional): hard cap on queued children. Default25.constraints(string, optional): shared input copied to every child.run_verify(boolean, optional): shared verification toggle copied to child implement presets. Defaulttrue.additional_jql(string, optional): advanced JQL AND-clause appended to the project/status query.issue_range(string, GitHub preset only): inclusiveSTART-ENDsearch criteria. Numeric members are targets only when GitHub returns an open Issue.repository(string, optional): repository override when workflow context cannot infer it.publish_mode(string, optional): advanced child publish override,none,branch,pr, orpr_with_merge_automation. Defaultnone.
Workflow
Resolve provider targets into the canonical resolved-target shape and write them to
artifacts/batch-workflows-targets.jsonbefore queueing.For Jira, use the trusted Jira tool surface to search and preview the list:
project = "<jira_project_key>" AND status = "<jira_status>"Append
additional_jqlonly when provided. Each target is:{ "provider": "jira", "ref": "MM-123", "jiraIssue": {"key": "MM-123", "summary": "...", "description": "...", "url": "...", "status": "In Progress", "assignee": "..."}, "repository": "MoonLadderStudios/MoonMind" }Never use raw Jira credentials, web scraping, or guessed issue content to build the target list.
For GitHub, the inclusive number range is search criteria, not a target list. GitHub issues and pull requests share numbers, and numbers may be absent. Use the helper's
--github-issue-rangeplus--github-repositoryinputs so its trusted GraphQLissue(number:)lookup returns only open Issue objects. Closed issues, pull requests, absent numbers, and responses without an explicit open state are omitted normally and never become targets. The helper rejects numeric spans wider than 1,000 numbers before querying GitHub and writes the resolved target artifact before queueing.Queue child workflows by running the helper:
python3 "$MOONMIND_ACTIVE_SKILLS_DIR/batch-workflows/bin/batch_workflows.py" \ --targets artifacts/batch-workflows-targets.json \ --run-ref <curated provider-specific run ref> \ --publish-mode <none|branch|pr|pr_with_merge_automation> \ --constraints-file <optional path to shared constraints> \ --run-verify | --no-run-verify \ --update-status | --no-update-status \ --max-workflows <cap>For the GitHub preset, replace
--targetswith:--github-issue-range <START-END> \ --github-repository <owner/repository>For each resolved target the helper:
- Auto-binds Jira issues into
skill:jira-verifyinputs (jira_issue,jira_issue_key,repository,verification_mode,update_status, andconstraints). - Auto-binds Jira issues into
preset:jira-implementinputs (jira_issue,jira_issue_key,constraints, andrun_verify). - Auto-binds the same Jira inputs into
preset:jira-orchestrate. - Auto-binds GitHub issue targets into the Implement and Orchestrate presets,
including
run_verify. - Stamps
runtimeInheritance="caller"plus a fallback copy of the parent's effective runtime (mode/model/effort/provider profile) so children reuse the caller runtime even on deployments that do not honour the inheritance contract. - Applies the chosen
publish.modeonce to every child. - Assigns a stable idempotency key per
(batch scope, provider, target kind, target slug, target ref)so rerunning the same batch does not create duplicate child workflows. - Submits via the internal Temporal execution API (
POST /api/executions);MOONMIND_URLmust point at the MoonMind API from the managed session. - When MoonMind supplies
MOONMIND_EXECUTION_FANOUT_BEARER_TOKEN, forwards it as the execution-scoped bearer and marks create and describe calls as fan-out v1.
If provider-specific input validation fails before a trustworthy target list can be written, still invoke the same helper exactly once with
--preflight-error <actionable message>and--requested-count <requested target count>. The helper records the current execution's authoritative failure in the managed artifact spool and does not read targets or queue children. Do not handcraft or reuse a repo-local result artifact.- Auto-binds Jira issues into
Record the summary: the helper writes
artifacts/batch-workflows-result.jsonlinking every queued child workflow id together with the resolved targets, skips, and errors, and prints a shortqueued/skipped/errorscount summary.
Safety constraints
- Require
MOONMIND_URLto reach the MoonMind API; the legacy direct-DB queue is not supported. - Never re-select provider/model/effort in the batch form; children inherit the caller runtime.
- Cap the resolved target list at
max_workflows; a GitHub range's numeric width is not the target count. Bound GitHub discovery independently to a maximum numeric span of 1,000. - Targets whose selected run capability is not auto-bindable are skipped with a
clear
unsupported_targetreason rather than queued blindly.