From c264d153b3f0a5081ec2a2d654cada48456a66df Mon Sep 17 00:00:00 2001 From: Cameron Cooke Date: Sun, 26 Apr 2026 20:12:23 +0100 Subject: [PATCH] docs(workflows): Document platform recommendations Carry workflow target platform metadata through the docs manifest pipeline so the workflows table can show platform recommendations once the upstream release includes the field. Explain how setup uses target platforms for recommendations without turning them into runtime gating. Co-Authored-By: Claude Code Opus Co-Authored-By: OpenAI Codex --- app/docs/_components/live.tsx | 18 ++++++++ .../architecture-manifest-visibility.mdx | 17 +++++++- app/docs/_content/setup.mdx | 10 +++++ app/docs/_data/fetch-manifest.ts | 11 +++++ app/docs/_data/manifests.ts | 42 ++++++++++++++++++- scripts/sync-xcodebuildmcp-manifests.mjs | 8 ++++ 6 files changed, 104 insertions(+), 2 deletions(-) diff --git a/app/docs/_components/live.tsx b/app/docs/_components/live.tsx index 0d445ac..f366854 100644 --- a/app/docs/_components/live.tsx +++ b/app/docs/_components/live.tsx @@ -34,11 +34,14 @@ export function LiveWorkflowToolCount({ workflow }: { workflow: string }) { export function LiveWorkflowsTable() { const manifest = useManifest() + const hasTargetPlatformData = manifest.workflows.some((w) => w.targetPlatforms.length > 0) + return ( + {hasTargetPlatformData ? : null} @@ -54,6 +57,21 @@ export function LiveWorkflowsTable() { ) : null} + {hasTargetPlatformData ? ( + + ) : null} diff --git a/app/docs/_content/architecture-manifest-visibility.mdx b/app/docs/_content/architecture-manifest-visibility.mdx index 58fa9c1..ce3ad31 100644 --- a/app/docs/_content/architecture-manifest-visibility.mdx +++ b/app/docs/_content/architecture-manifest-visibility.mdx @@ -29,7 +29,7 @@ Keeping that metadata in YAML prevents each runtime from inventing its own catal | Directory | Defines | Used by | |-----------|---------|---------| | `manifests/tools/` | Tool ID, implementation module, MCP and CLI names, description, annotations, availability, predicates, routing, next steps, output schema metadata. | MCP registration, CLI command generation, daemon catalog, generated docs, schema checks. | -| `manifests/workflows/` | Workflow ID and tool membership. | Workflow selection, sidebar grouping in generated references, MCP catalog trimming. | +| `manifests/workflows/` | Workflow ID, tool membership, and `targetPlatforms` setup guidance. | Workflow selection, sidebar grouping in generated references, MCP catalog trimming, setup wizard recommendations. | | `manifests/resources/` | MCP resource metadata and module handler. | MCP resource registration. | Tool modules are imported only after the manifest has been loaded and filtered. A tool module must export named `schema` and `handler` values. Resource modules have their own contract and require a handler, so avoid treating the tool-module contract as universal. @@ -83,6 +83,21 @@ Workflow selection is the coarse catalog control. It keeps MCP sessions small an That order matters for contributors. Put durable product grouping in workflow manifests. Put conditional exposure in predicates. Put public runtime support in the `availability` object. +## Workflow `targetPlatforms` is setup guidance, not exposure + +Workflow manifests carry a `targetPlatforms` field listing the Apple platforms (`iOS`, `macOS`, `tvOS`, `watchOS`, `visionOS`) the workflow is recommended for. The setup wizard reads this to ask the user which platforms they target and to highlight matching workflows. The conservative default selection stays narrow: `simulator` for any simulator platform, `macos` when macOS is selected. Everything else is recommended-but-opt-in, and the user can still pick any workflow regardless of platform. + +A few things `targetPlatforms` is deliberately not: + +- Not an exposure check. It does not replace predicates, the `availability` object, or per-tool capability checks at runtime. +- Not unsupported when empty. `targetPlatforms: []` means the workflow is not specific to a target platform (typical for `session-management`, `workflow-discovery`, or `doctor`); it is still exposed normally. +- Not authoritative for individual tools. It describes the workflow as a unit; tool-level platform support stays in the implementation and predicates. + +When authoring a new workflow: + +- Set `targetPlatforms` to every platform the workflow is genuinely useful on. `swift-package` covers all five Apple platforms; `macos` is `macOS` only; `ui-automation` is `iOS` only today. +- Leave `targetPlatforms: []` for workflows that are not user-selected by platform (session management, workflow discovery, doctor). + ## Authoring implications When adding or changing a tool, update the manifest first enough to make the intended exposure explicit: diff --git a/app/docs/_content/setup.mdx b/app/docs/_content/setup.mdx index 8447c80..1180b85 100644 --- a/app/docs/_content/setup.mdx +++ b/app/docs/_content/setup.mdx @@ -31,6 +31,7 @@ xcodebuildmcp setup The wizard walks you through: +- **Target platforms**: which Apple platforms you build for (macOS, iOS, tvOS, watchOS, visionOS). Selecting at least one platform shapes the rest of the wizard, including which workflows are recommended and whether you need to pick a simulator. - **Workflows**: which tool groups to enable (simulator, device, macOS, debugging, UI automation, etc.) - **Project defaults**: your workspace or project path, scheme, configuration - **Simulator defaults**: preferred simulator by name or UDID @@ -38,6 +39,15 @@ The wizard walks you through: Non-interactive mode is available for CI and scripts (`xcodebuildmcp setup --help`). +### Recommended vs default workflows + +The wizard splits workflows into two groups based on your target platforms: + +- **Recommended**: workflows whose `targetPlatforms` overlap your selection. The wizard pre-selects only the conservative defaults: `simulator` for any simulator platform (iOS, tvOS, watchOS, visionOS) and `macos` when macOS is selected. Other recommended workflows (for example `device`, `debugging`, `ui-automation`, `swift-package`) are listed alongside but left unchecked, so you opt in to what you need. +- **Additional**: every other workflow. These are still selectable, just not flagged as a fit for your platforms. + +Target platforms are guidance for setup only. They do not gate tool exposure at runtime: any workflow you enable still advertises its tools through MCP regardless of platform metadata. Predicates and the `availability` field handle runtime gating, see [Workflows](/docs/workflows) and [MCP Server Mode → Workflow selection](/docs/mcp-mode#workflow-selection) for the full picture. + If your client doesn't read `.xcodebuildmcp/config.yaml` from the workspace (some don't), you can export an env-based config block with `xcodebuildmcp setup --format mcp-json` and paste it into your MCP client config. diff --git a/app/docs/_data/fetch-manifest.ts b/app/docs/_data/fetch-manifest.ts index f1e6406..a81828e 100644 --- a/app/docs/_data/fetch-manifest.ts +++ b/app/docs/_data/fetch-manifest.ts @@ -2,9 +2,11 @@ import "server-only" import { load as loadYaml } from "js-yaml" import { BUNDLED_MANIFEST, + WORKFLOW_TARGET_PLATFORMS, type ManifestSnapshot, type ToolEntry, type WorkflowEntry, + type WorkflowTargetPlatform, } from "./manifests" const REPO = "getsentry/XcodeBuildMCP" @@ -94,6 +96,14 @@ function normalizeTools(raw: Array>): ToolEntry[] { .sort((a, b) => a.mcpName.localeCompare(b.mcpName)) } +function normalizeTargetPlatforms(value: unknown): WorkflowTargetPlatform[] { + if (!Array.isArray(value)) return [] + return value.filter( + (p): p is WorkflowTargetPlatform => + typeof p === "string" && (WORKFLOW_TARGET_PLATFORMS as readonly string[]).includes(p) + ) +} + function normalizeWorkflows(raw: Array>): WorkflowEntry[] { return raw .map((w) => { @@ -104,6 +114,7 @@ function normalizeWorkflows(raw: Array>): WorkflowEntry[ title: (w.title as string | undefined) ?? String(w.id ?? ""), description: (w.description as string | undefined) ?? "", defaultEnabled: Boolean(selection.mcp?.defaultEnabled), + targetPlatforms: normalizeTargetPlatforms(w.targetPlatforms), tools: Array.isArray(w.tools) ? (w.tools as string[]) : [], } }) diff --git a/app/docs/_data/manifests.ts b/app/docs/_data/manifests.ts index 1c6e52a..166d137 100644 --- a/app/docs/_data/manifests.ts +++ b/app/docs/_data/manifests.ts @@ -13,11 +13,22 @@ export interface ToolEntry { predicates: string[] } +export const WORKFLOW_TARGET_PLATFORMS = [ + "iOS", + "macOS", + "tvOS", + "watchOS", + "visionOS", +] as const + +export type WorkflowTargetPlatform = (typeof WORKFLOW_TARGET_PLATFORMS)[number] + export interface WorkflowEntry { id: string title: string description: string defaultEnabled: boolean + targetPlatforms: WorkflowTargetPlatform[] tools: string[] } @@ -30,11 +41,40 @@ export interface ManifestSnapshot { tools: ToolEntry[] } +function normalizeBundledWorkflow(w: Record): WorkflowEntry { + const platforms = Array.isArray(w.targetPlatforms) + ? (w.targetPlatforms as unknown[]).filter( + (p): p is WorkflowTargetPlatform => + typeof p === "string" && + (WORKFLOW_TARGET_PLATFORMS as readonly string[]).includes(p) + ) + : [] + return { + id: String(w.id ?? ""), + title: typeof w.title === "string" ? w.title : String(w.id ?? ""), + description: typeof w.description === "string" ? w.description : "", + defaultEnabled: Boolean(w.defaultEnabled), + targetPlatforms: platforms, + tools: Array.isArray(w.tools) ? (w.tools as string[]) : [], + } +} + /** * Bundled snapshot from `pnpm run docs:sync`. Used as a fallback when the * GitHub API is unreachable or rate-limited at request time. + * + * Snapshots produced before workflows gained `targetPlatforms` are tolerated + * by defaulting the field to an empty array. */ -export const BUNDLED_MANIFEST: ManifestSnapshot = snapshot as ManifestSnapshot +export const BUNDLED_MANIFEST: ManifestSnapshot = (() => { + const raw = snapshot as Omit & { + workflows: Array> + } + return { + ...raw, + workflows: raw.workflows.map(normalizeBundledWorkflow), + } as ManifestSnapshot +})() /** * Default export for legacy imports that haven't migrated to the provider diff --git a/scripts/sync-xcodebuildmcp-manifests.mjs b/scripts/sync-xcodebuildmcp-manifests.mjs index be5f1ab..4717553 100644 --- a/scripts/sync-xcodebuildmcp-manifests.mjs +++ b/scripts/sync-xcodebuildmcp-manifests.mjs @@ -130,6 +130,13 @@ function normalizeTools(raw) { .sort((a, b) => a.mcpName.localeCompare(b.mcpName)) } +const WORKFLOW_TARGET_PLATFORMS = new Set(["iOS", "macOS", "tvOS", "watchOS", "visionOS"]) + +function normalizeTargetPlatforms(value) { + if (!Array.isArray(value)) return [] + return value.filter((p) => typeof p === "string" && WORKFLOW_TARGET_PLATFORMS.has(p)) +} + function normalizeWorkflows(raw) { return raw .map((w) => ({ @@ -137,6 +144,7 @@ function normalizeWorkflows(raw) { title: w.title ?? w.id, description: w.description ?? "", defaultEnabled: Boolean(w.selection?.mcp?.defaultEnabled), + targetPlatforms: normalizeTargetPlatforms(w.targetPlatforms), tools: Array.isArray(w.tools) ? w.tools : [], })) .sort((a, b) => a.id.localeCompare(b.id))
WorkflowRecommended forTools Description
+ {w.targetPlatforms.length > 0 ? ( + + {w.targetPlatforms.map((platform) => ( + + {platform} + + ))} + + ) : ( + not platform-specific + )} + {w.tools.length} {w.description}