diff --git a/.changeset/patch-add-explanatory-output-style-plugin.md b/.changeset/patch-add-explanatory-output-style-plugin.md new file mode 100644 index 0000000000..14dc4eb852 --- /dev/null +++ b/.changeset/patch-add-explanatory-output-style-plugin.md @@ -0,0 +1,5 @@ +--- +"gh-aw": patch +--- + +Fixed plugin import format in smoke workflows from marketplace URL syntax (`explanatory-output-style@claude-plugins-official`) to GitHub repository path (`anthropics/claude-code/plugins/explanatory-output-style`). The marketplace URL format was not recognized by the Copilot CLI, causing smoke test failures. Updated documentation and schema to clarify that plugins must use GitHub repository paths. diff --git a/.changeset/patch-explanatory-output-style-plugin.md b/.changeset/patch-explanatory-output-style-plugin.md new file mode 100644 index 0000000000..07e0e9a326 --- /dev/null +++ b/.changeset/patch-explanatory-output-style-plugin.md @@ -0,0 +1,5 @@ +--- +"gh-aw": patch +--- + +Document the smoke workflow changes that install the explanatory-output-style plugin via the marketplace URL syntax, plus schema updates and MCP config support. diff --git a/.github/workflows/smoke-claude.lock.yml b/.github/workflows/smoke-claude.lock.yml index 19e018ee5d..54c29c2834 100644 --- a/.github/workflows/smoke-claude.lock.yml +++ b/.github/workflows/smoke-claude.lock.yml @@ -32,7 +32,7 @@ # - shared/mood.md # - shared/reporting.md # -# frontmatter-hash: 0837bbb92b5a6973ee2770c91b853a91e6e5113d590fd52ff842d31d1a8bcfd5 +# frontmatter-hash: 814364c13cedc40d83bd313a6a4fb190c33e8b2361c298259e94560c394117ec name: "Smoke Claude" "on": @@ -233,6 +233,10 @@ jobs: run: bash /opt/gh-aw/actions/install_awf_binary.sh v0.13.12 - name: Install Claude Code CLI run: npm install -g --silent @anthropic-ai/claude-code@2.1.34 + - name: 'Install plugin: anthropics/claude-code/plugins/explanatory-output-style' + env: + GITHUB_TOKEN: ${{ secrets.GH_AW_PLUGINS_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + run: claude plugin install anthropics/claude-code/plugins/explanatory-output-style - name: Determine automatic lockdown mode for GitHub MCP server id: determine-automatic-lockdown env: @@ -1584,11 +1588,12 @@ jobs: const { main } = require('/opt/gh-aw/actions/redact_secrets.cjs'); await main(); env: - GH_AW_SECRET_NAMES: 'ANTHROPIC_API_KEY,CLAUDE_CODE_OAUTH_TOKEN,GH_AW_GITHUB_MCP_SERVER_TOKEN,GH_AW_GITHUB_TOKEN,GITHUB_TOKEN,TAVILY_API_KEY' + GH_AW_SECRET_NAMES: 'ANTHROPIC_API_KEY,CLAUDE_CODE_OAUTH_TOKEN,GH_AW_GITHUB_MCP_SERVER_TOKEN,GH_AW_GITHUB_TOKEN,GH_AW_PLUGINS_TOKEN,GITHUB_TOKEN,TAVILY_API_KEY' SECRET_ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} SECRET_CLAUDE_CODE_OAUTH_TOKEN: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} SECRET_GH_AW_GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN }} SECRET_GH_AW_GITHUB_TOKEN: ${{ secrets.GH_AW_GITHUB_TOKEN }} + SECRET_GH_AW_PLUGINS_TOKEN: ${{ secrets.GH_AW_PLUGINS_TOKEN }} SECRET_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SECRET_TAVILY_API_KEY: ${{ secrets.TAVILY_API_KEY }} - name: Upload Safe Outputs diff --git a/.github/workflows/smoke-claude.md b/.github/workflows/smoke-claude.md index 1c8913552c..57597f066e 100644 --- a/.github/workflows/smoke-claude.md +++ b/.github/workflows/smoke-claude.md @@ -18,6 +18,8 @@ name: Smoke Claude engine: id: claude max-turns: 15 +plugins: + - anthropics/claude-code/plugins/explanatory-output-style strict: true imports: - shared/mood.md diff --git a/.github/workflows/smoke-copilot.lock.yml b/.github/workflows/smoke-copilot.lock.yml index bb8231244e..786300494d 100644 --- a/.github/workflows/smoke-copilot.lock.yml +++ b/.github/workflows/smoke-copilot.lock.yml @@ -28,7 +28,7 @@ # - shared/mood.md # - shared/reporting.md # -# frontmatter-hash: b81319e0683d2730b59ce3601546860e0914e8a155eb123d3c913de9f7737264 +# frontmatter-hash: 875717e5ae342cffe17b69a248ab1eacf41332cc6cb9e332995967f31013e6d8 name: "Smoke Copilot" "on": @@ -223,6 +223,10 @@ jobs: run: /opt/gh-aw/actions/install_copilot_cli.sh 0.0.405 - name: Install awf binary run: bash /opt/gh-aw/actions/install_awf_binary.sh v0.13.12 + - name: 'Install plugin: anthropics/claude-code/plugins/explanatory-output-style' + env: + GITHUB_TOKEN: ${{ secrets.GH_AW_PLUGINS_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + run: copilot plugin install anthropics/claude-code/plugins/explanatory-output-style - name: Determine automatic lockdown mode for GitHub MCP server id: determine-automatic-lockdown env: @@ -1407,7 +1411,7 @@ jobs: run: | set -o pipefail sudo -E awf --enable-chroot --env-all --container-workdir "${GITHUB_WORKSPACE}" --allow-domains '*.githubusercontent.com,*.jsr.io,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.npms.io,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,bun.sh,cdn.playwright.dev,codeload.github.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,deb.nodesource.com,deno.land,get.pnpm.io,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.com,github.githubassets.com,go.dev,golang.org,goproxy.io,host.docker.internal,json-schema.org,json.schemastore.org,jsr.io,keyserver.ubuntu.com,lfs.github.com,nodejs.org,npm.pkg.github.com,npmjs.com,npmjs.org,objects.githubusercontent.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,pkg.go.dev,playwright.download.prss.microsoft.com,ppa.launchpad.net,proxy.golang.org,raw.githubusercontent.com,registry.bower.io,registry.npmjs.com,registry.npmjs.org,registry.yarnpkg.com,repo.yarnpkg.com,s.symcb.com,s.symcd.com,security.ubuntu.com,skimdb.npmjs.com,sum.golang.org,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.npmjs.com,www.npmjs.org,yarnpkg.com' --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --enable-host-access --image-tag 0.13.12 --skip-pull \ - -- '/usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --add-dir "${GITHUB_WORKSPACE}" --disable-builtin-mcps --allow-all-tools --add-dir /tmp/gh-aw/cache-memory/ --allow-all-paths --share /tmp/gh-aw/sandbox/agent/logs/conversation.md --prompt "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"${GH_AW_MODEL_AGENT_COPILOT:+ --model "$GH_AW_MODEL_AGENT_COPILOT"}' \ + -- '/usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --add-dir "${GITHUB_WORKSPACE}" --add-dir /home/runner/.copilot/ --disable-builtin-mcps --allow-all-tools --add-dir /tmp/gh-aw/cache-memory/ --allow-all-paths --share /tmp/gh-aw/sandbox/agent/logs/conversation.md --prompt "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"${GH_AW_MODEL_AGENT_COPILOT:+ --model "$GH_AW_MODEL_AGENT_COPILOT"}' \ 2>&1 | tee /tmp/gh-aw/agent-stdio.log env: COPILOT_AGENT_RUNNER_TYPE: STANDALONE @@ -1458,10 +1462,11 @@ jobs: const { main } = require('/opt/gh-aw/actions/redact_secrets.cjs'); await main(); env: - GH_AW_SECRET_NAMES: 'COPILOT_GITHUB_TOKEN,GH_AW_GITHUB_MCP_SERVER_TOKEN,GH_AW_GITHUB_TOKEN,GITHUB_TOKEN' + GH_AW_SECRET_NAMES: 'COPILOT_GITHUB_TOKEN,GH_AW_GITHUB_MCP_SERVER_TOKEN,GH_AW_GITHUB_TOKEN,GH_AW_PLUGINS_TOKEN,GITHUB_TOKEN' SECRET_COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} SECRET_GH_AW_GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN }} SECRET_GH_AW_GITHUB_TOKEN: ${{ secrets.GH_AW_GITHUB_TOKEN }} + SECRET_GH_AW_PLUGINS_TOKEN: ${{ secrets.GH_AW_PLUGINS_TOKEN }} SECRET_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Upload Safe Outputs if: always() diff --git a/.github/workflows/smoke-copilot.md b/.github/workflows/smoke-copilot.md index c30b0ce8df..5a47849920 100644 --- a/.github/workflows/smoke-copilot.md +++ b/.github/workflows/smoke-copilot.md @@ -15,6 +15,8 @@ permissions: actions: read name: Smoke Copilot engine: copilot +plugins: + - anthropics/claude-code/plugins/explanatory-output-style imports: - shared/mood.md - shared/gh.md diff --git a/.github/workflows/smoke-test-tools.lock.yml b/.github/workflows/smoke-test-tools.lock.yml index 22efec80a8..8576136c1e 100644 --- a/.github/workflows/smoke-test-tools.lock.yml +++ b/.github/workflows/smoke-test-tools.lock.yml @@ -25,7 +25,7 @@ # Imports: # - shared/mood.md # -# frontmatter-hash: 7d3e13ff178d7cd42b27a1498d76b1ba1b3ecda4d8027c84c8b6611647084fba +# frontmatter-hash: 0897bff6c9f6cc36ba1c2bb267dfb3f5517ac7af6dfe29f6c1d95fe23a18cf9d name: "Agent Container Smoke Test" "on": @@ -179,6 +179,10 @@ jobs: run: /opt/gh-aw/actions/install_copilot_cli.sh 0.0.405 - name: Install awf binary run: bash /opt/gh-aw/actions/install_awf_binary.sh v0.13.12 + - name: 'Install plugin: anthropics/claude-code/plugins/explanatory-output-style' + env: + GITHUB_TOKEN: ${{ secrets.GH_AW_PLUGINS_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + run: copilot plugin install anthropics/claude-code/plugins/explanatory-output-style - name: Determine automatic lockdown mode for GitHub MCP server id: determine-automatic-lockdown env: @@ -617,7 +621,7 @@ jobs: run: | set -o pipefail sudo -E awf --enable-chroot --env-all --container-workdir "${GITHUB_WORKSPACE}" --allow-domains '*.githubusercontent.com,*.jsr.io,*.pythonhosted.org,adoptium.net,anaconda.org,api.adoptium.net,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.foojay.io,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.npms.io,api.nuget.org,api.snapcraft.io,archive.apache.org,archive.ubuntu.com,azure.archive.ubuntu.com,azuresearch-usnc.nuget.org,azuresearch-ussc.nuget.org,binstar.org,bootstrap.pypa.io,builds.dotnet.microsoft.com,bun.sh,cdn.azul.com,ci.dot.net,codeload.github.com,conda.anaconda.org,conda.binstar.org,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,dc.services.visualstudio.com,deb.nodesource.com,deno.land,dist.nuget.org,dlcdn.apache.org,dot.net,dotnet.microsoft.com,dotnetcli.blob.core.windows.net,download.eclipse.org,download.java.net,download.oracle.com,files.pythonhosted.org,get.pnpm.io,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.com,github.githubassets.com,go.dev,golang.org,goproxy.io,gradle.org,host.docker.internal,jcenter.bintray.com,jdk.java.net,json-schema.org,json.schemastore.org,jsr.io,keyserver.ubuntu.com,lfs.github.com,maven.apache.org,maven.oracle.com,maven.pkg.github.com,nodejs.org,npm.pkg.github.com,npmjs.com,npmjs.org,nuget.org,nuget.pkg.github.com,nugetregistryv2prod.blob.core.windows.net,objects.githubusercontent.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,oneocsp.microsoft.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,pip.pypa.io,pkg.go.dev,pkgs.dev.azure.com,plugins-artifacts.gradle.org,plugins.gradle.org,ppa.launchpad.net,proxy.golang.org,pypi.org,pypi.python.org,raw.githubusercontent.com,registry.bower.io,registry.npmjs.com,registry.npmjs.org,registry.yarnpkg.com,repo.anaconda.com,repo.continuum.io,repo.grails.org,repo.maven.apache.org,repo.spring.io,repo.yarnpkg.com,repo1.maven.org,s.symcb.com,s.symcd.com,security.ubuntu.com,services.gradle.org,skimdb.npmjs.com,sum.golang.org,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.java.com,www.microsoft.com,www.npmjs.com,www.npmjs.org,yarnpkg.com' --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --enable-host-access --image-tag 0.13.12 --skip-pull \ - -- '/usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --add-dir "${GITHUB_WORKSPACE}" --disable-builtin-mcps --allow-all-tools --allow-all-paths --share /tmp/gh-aw/sandbox/agent/logs/conversation.md --prompt "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"${GH_AW_MODEL_AGENT_COPILOT:+ --model "$GH_AW_MODEL_AGENT_COPILOT"}' \ + -- '/usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --add-dir "${GITHUB_WORKSPACE}" --add-dir /home/runner/.copilot/ --disable-builtin-mcps --allow-all-tools --allow-all-paths --share /tmp/gh-aw/sandbox/agent/logs/conversation.md --prompt "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"${GH_AW_MODEL_AGENT_COPILOT:+ --model "$GH_AW_MODEL_AGENT_COPILOT"}' \ 2>&1 | tee /tmp/gh-aw/agent-stdio.log env: COPILOT_AGENT_RUNNER_TYPE: STANDALONE @@ -667,10 +671,11 @@ jobs: const { main } = require('/opt/gh-aw/actions/redact_secrets.cjs'); await main(); env: - GH_AW_SECRET_NAMES: 'COPILOT_GITHUB_TOKEN,GH_AW_GITHUB_MCP_SERVER_TOKEN,GH_AW_GITHUB_TOKEN,GITHUB_TOKEN' + GH_AW_SECRET_NAMES: 'COPILOT_GITHUB_TOKEN,GH_AW_GITHUB_MCP_SERVER_TOKEN,GH_AW_GITHUB_TOKEN,GH_AW_PLUGINS_TOKEN,GITHUB_TOKEN' SECRET_COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} SECRET_GH_AW_GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN }} SECRET_GH_AW_GITHUB_TOKEN: ${{ secrets.GH_AW_GITHUB_TOKEN }} + SECRET_GH_AW_PLUGINS_TOKEN: ${{ secrets.GH_AW_PLUGINS_TOKEN }} SECRET_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Upload Safe Outputs if: always() diff --git a/.github/workflows/smoke-test-tools.md b/.github/workflows/smoke-test-tools.md index c5dd62a322..bc35489a9e 100644 --- a/.github/workflows/smoke-test-tools.md +++ b/.github/workflows/smoke-test-tools.md @@ -12,6 +12,8 @@ permissions: pull-requests: read name: Agent Container Smoke Test engine: copilot +plugins: + - anthropics/claude-code/plugins/explanatory-output-style strict: true runtimes: node: diff --git a/docs/src/content/docs/reference/frontmatter.md b/docs/src/content/docs/reference/frontmatter.md index ebb3da56f1..b2c3d475c8 100644 --- a/docs/src/content/docs/reference/frontmatter.md +++ b/docs/src/content/docs/reference/frontmatter.md @@ -107,6 +107,7 @@ Specifies plugins to install before workflow execution. Plugins are installed us plugins: - github/test-plugin - acme/custom-tools + - anthropics/claude-code/plugins/explanatory-output-style ``` **Object format** (with custom token): @@ -118,6 +119,12 @@ plugins: github-token: ${{ secrets.CUSTOM_PLUGIN_TOKEN }} ``` +**Plugin identifier formats:** +- **GitHub repository**: `org/repo` (e.g., `github/test-plugin`) +- **Sub-plugin path**: `org/repo/path/to/plugin` (e.g., `anthropics/claude-code/plugins/explanatory-output-style`) + +**Note**: The plugin format must be compatible with the engine's CLI `plugin install` command. Currently, GitHub repository paths (with optional sub-paths) are the standard format supported across engines. + **Token precedence** for plugin installation (highest to lowest): 1. Custom `plugins.github-token` from object format 2. Custom top-level `github-token` @@ -125,7 +132,7 @@ plugins: 4. `${{ secrets.GH_AW_GITHUB_TOKEN }}` 5. `${{ secrets.GITHUB_TOKEN }}` (default) -Each plugin repository must be specified in `org/repo` format. The compiler generates installation steps that run after the engine CLI is installed but before workflow execution begins. +The compiler generates installation steps that run after the engine CLI is installed but before workflow execution begins. ### Runtimes (`runtimes:`) diff --git a/pkg/parser/schemas/main_workflow_schema.json b/pkg/parser/schemas/main_workflow_schema.json index 53bac0b92f..bcb9bf2e10 100644 --- a/pkg/parser/schemas/main_workflow_schema.json +++ b/pkg/parser/schemas/main_workflow_schema.json @@ -2483,9 +2483,10 @@ ] }, "plugins": { - "description": "Plugin configuration for installing plugins before workflow execution. Supports array format (list of repos/plugin configs) and object format (repos + custom token).", + "description": "Plugin configuration for installing plugins before workflow execution. Supports array format (list of repos/plugin configs) and object format (repos + custom token). Plugin paths can include sub-paths to specific plugins within a repository (e.g., 'anthropics/claude-code/plugins/explanatory-output-style').", "examples": [ ["github/copilot-plugin", "acme/custom-tools"], + ["anthropics/claude-code/plugins/explanatory-output-style"], [ "github/simple-plugin", { @@ -2510,8 +2511,8 @@ "oneOf": [ { "type": "string", - "pattern": "^[a-zA-Z0-9_-]+/[a-zA-Z0-9_-]+$", - "description": "Plugin repository slug in the format 'org/repo' (e.g., 'github/example-plugin')" + "pattern": "^([a-zA-Z0-9_-]+(/[a-zA-Z0-9_-]+)+|[a-zA-Z0-9_-]+)(@[a-zA-Z0-9_-]+)?$", + "description": "Plugin identifier in GitHub repository format: 'org/repo' or 'org/repo/path/to/plugin' (e.g., 'github/example-plugin', 'anthropics/claude-code/plugins/explanatory-output-style'). The pattern allows @marketplace syntax for potential future support, but current engines only support GitHub repository paths." }, { "type": "object", @@ -2520,8 +2521,8 @@ "properties": { "id": { "type": "string", - "pattern": "^[a-zA-Z0-9_-]+/[a-zA-Z0-9_-]+$", - "description": "Plugin repository slug in the format 'org/repo' (e.g., 'github/example-plugin')" + "pattern": "^([a-zA-Z0-9_-]+(/[a-zA-Z0-9_-]+)+|[a-zA-Z0-9_-]+)(@[a-zA-Z0-9_-]+)?$", + "description": "Plugin repository slug in GitHub repository format: 'org/repo' or 'org/repo/path/to/plugin' (e.g., 'github/example-plugin', 'anthropics/claude-code/plugins/explanatory-output-style')" }, "mcp": { "type": "object", @@ -2561,8 +2562,8 @@ "oneOf": [ { "type": "string", - "pattern": "^[a-zA-Z0-9_-]+/[a-zA-Z0-9_-]+$", - "description": "Plugin repository slug in the format 'org/repo' (e.g., 'github/example-plugin')" + "pattern": "^([a-zA-Z0-9_-]+(/[a-zA-Z0-9_-]+)+|[a-zA-Z0-9_-]+)(@[a-zA-Z0-9_-]+)?$", + "description": "Plugin identifier in GitHub repository format: 'org/repo' or 'org/repo/path/to/plugin' (e.g., 'github/example-plugin', 'anthropics/claude-code/plugins/explanatory-output-style'). The pattern allows @marketplace syntax for potential future support, but current engines only support GitHub repository paths." }, { "type": "object", @@ -2571,8 +2572,8 @@ "properties": { "id": { "type": "string", - "pattern": "^[a-zA-Z0-9_-]+/[a-zA-Z0-9_-]+$", - "description": "Plugin repository slug in the format 'org/repo' (e.g., 'github/example-plugin')" + "pattern": "^([a-zA-Z0-9_-]+(/[a-zA-Z0-9_-]+)+|[a-zA-Z0-9_-]+)(@[a-zA-Z0-9_-]+)?$", + "description": "Plugin repository slug in the format 'org/repo', 'org/repo/path/to/plugin', 'plugin-name@marketplace', or 'org/repo@marketplace' (e.g., 'github/example-plugin', 'anthropics/claude-code/plugins/explanatory-output-style')" }, "mcp": { "type": "object", diff --git a/pkg/workflow/agentic_engine.go b/pkg/workflow/agentic_engine.go index 2c1a446549..c6b696b8d5 100644 --- a/pkg/workflow/agentic_engine.go +++ b/pkg/workflow/agentic_engine.go @@ -125,6 +125,10 @@ type CapabilityProvider interface { // SupportsFirewall returns true if this engine supports network firewalling/sandboxing // When true, the engine can enforce network restrictions defined in the workflow SupportsFirewall() bool + + // SupportsPlugins returns true if this engine supports plugin installation + // When true, plugins can be installed using the engine's plugin install command + SupportsPlugins() bool } // WorkflowExecutor handles workflow compilation and execution @@ -199,6 +203,7 @@ type BaseEngine struct { supportsWebFetch bool supportsWebSearch bool supportsFirewall bool + supportsPlugins bool } func (e *BaseEngine) GetID() string { @@ -241,6 +246,10 @@ func (e *BaseEngine) SupportsFirewall() bool { return e.supportsFirewall } +func (e *BaseEngine) SupportsPlugins() bool { + return e.supportsPlugins +} + // GetDeclaredOutputFiles returns an empty list by default (engines can override) func (e *BaseEngine) GetDeclaredOutputFiles() []string { return []string{} diff --git a/pkg/workflow/claude_engine.go b/pkg/workflow/claude_engine.go index 3c1f0eda90..6618a75820 100644 --- a/pkg/workflow/claude_engine.go +++ b/pkg/workflow/claude_engine.go @@ -25,11 +25,12 @@ func NewClaudeEngine() *ClaudeEngine { description: "Uses Claude Code with full MCP tool support and allow-listing", experimental: false, supportsToolsAllowlist: true, - supportsHTTPTransport: true, // Claude supports both stdio and HTTP transport - supportsMaxTurns: true, // Claude supports max-turns feature - supportsWebFetch: true, // Claude has built-in WebFetch support - supportsWebSearch: true, // Claude has built-in WebSearch support - supportsFirewall: true, // Claude supports network firewalling via AWF + supportsHTTPTransport: true, // Claude supports both stdio and HTTP transport + supportsMaxTurns: true, // Claude supports max-turns feature + supportsWebFetch: true, // Claude has built-in WebFetch support + supportsWebSearch: true, // Claude has built-in WebSearch support + supportsFirewall: true, // Claude supports network firewalling via AWF + supportsPlugins: true, // Claude supports plugin installation }, } } diff --git a/pkg/workflow/codex_engine.go b/pkg/workflow/codex_engine.go index 6f8d49e593..193edb6553 100644 --- a/pkg/workflow/codex_engine.go +++ b/pkg/workflow/codex_engine.go @@ -41,6 +41,7 @@ func NewCodexEngine() *CodexEngine { supportsWebFetch: false, // Codex does not have built-in web-fetch support supportsWebSearch: true, // Codex has built-in web-search support supportsFirewall: true, // Codex supports network firewalling via AWF + supportsPlugins: false, // Codex does not support plugin installation }, } } diff --git a/pkg/workflow/compiler_orchestrator_tools.go b/pkg/workflow/compiler_orchestrator_tools.go index 964f8a9a8c..5147f95ae1 100644 --- a/pkg/workflow/compiler_orchestrator_tools.go +++ b/pkg/workflow/compiler_orchestrator_tools.go @@ -180,6 +180,15 @@ func (c *Compiler) processToolsAndMarkdown(result *parser.FrontmatterResult, cle orchestratorToolsLog.Printf("Merged plugins: %d total unique plugins", len(pluginInfo.Plugins)) } + // Validate that the engine supports plugins if plugins are configured + if pluginInfo != nil && len(pluginInfo.Plugins) > 0 { + if !agenticEngine.SupportsPlugins() { + pluginList := strings.Join(pluginInfo.Plugins, ", ") + return nil, fmt.Errorf("engine '%s' does not support plugin installation. Plugins specified: %s. Only Copilot and Claude engines support plugins. Please remove the 'plugins:' field from your workflow or use a different engine", agenticEngine.GetID(), pluginList) + } + orchestratorToolsLog.Printf("Plugin support validation passed for engine: %s", agenticEngine.GetID()) + } + // Add MCP fetch server if needed (when web-fetch is requested but engine doesn't support it) tools, _ = AddMCPFetchServerIfNeeded(tools, agenticEngine) diff --git a/pkg/workflow/copilot_engine.go b/pkg/workflow/copilot_engine.go index cef6673186..4549c4075f 100644 --- a/pkg/workflow/copilot_engine.go +++ b/pkg/workflow/copilot_engine.go @@ -45,6 +45,7 @@ func NewCopilotEngine() *CopilotEngine { supportsWebFetch: true, // Copilot CLI has built-in web-fetch support supportsWebSearch: false, // Copilot CLI does not have built-in web-search support supportsFirewall: true, // Copilot supports network firewalling via AWF + supportsPlugins: true, // Copilot supports plugin installation }, } } diff --git a/pkg/workflow/custom_engine.go b/pkg/workflow/custom_engine.go index f938409a83..6ee322d7e9 100644 --- a/pkg/workflow/custom_engine.go +++ b/pkg/workflow/custom_engine.go @@ -26,6 +26,7 @@ func NewCustomEngine() *CustomEngine { supportsMaxTurns: true, // Custom engine supports max-turns for consistency supportsWebFetch: false, // Custom engine does not have built-in web-fetch support supportsWebSearch: false, // Custom engine does not have built-in web-search support + supportsPlugins: false, // Custom engine does not support plugin installation }, } }