{ "$schema": "https://json-schema.org/draft/2020-12/schema", "schema_version": "0.1", "name": "agents-shipgate-triggers", "description": "Machine-readable trigger catalog for Agents Shipgate. Mirrors the AGENTS.md trigger table — a coding agent that has not yet adopted Shipgate can fetch this and apply the rules to a PR diff or repo state to decide whether to run `agents-shipgate detect`. Stable for 0.x: rule IDs, predicate vocabulary, and action enum will not change in minor versions.", "source_of_truth": "AGENTS.md#should-i-run-shipgate-on-this-pr", "documentation_url": "https://github.com/ThreeMoonsLab/agents-shipgate/blob/main/AGENTS.md", "default_command": "agents-shipgate detect --workspace . --json", "predicate_vocabulary": { "glob": "Any changed file in the PR matches the glob (relative to repo root). Globstar `**` matches zero or more path segments; `*` matches within a segment; brace expansion is not supported.", "diff_contains": "The unified diff (added or modified lines) of this PR contains the literal string. Use only with stable token forms — decorator names, package names, function calls.", "file_present": "The named path exists in the working tree at the head commit, regardless of whether this PR changed it.", "file_absent": "The named path does NOT exist in the working tree at the head commit.", "every_file_matches": "Every changed file in this PR matches at least one of the listed globs (or the single glob, if a string). False on an empty PR.", "none_match_glob": "No changed file matches any of the listed globs.", "any_of": "Logical OR over a list of nested predicates.", "all_of": "Logical AND over a list of nested predicates.", "detect_returns": "Result of `agents-shipgate detect --workspace . --json` matches the given `key: value` pair (`is_agent_project: false`, `suggested_sources: []`, etc.). Used in `stop_conditions` only.", "user_did_not_request": "The user did not explicitly ask for a Shipgate run in their prompt. Used in `stop_conditions` only." }, "rules": [ { "id": "TRIGGER-MCP-EXPORT-CHANGED", "agents_md_row": "Adds/changes MCP exports, OpenAPI specs, or `tools/*openai*tools*.json`", "when": { "any_of": [ {"glob": "**/*mcp*.json"}, {"glob": ".agents-shipgate/*.json"} ] }, "action": "run_shipgate", "rationale": "MCP exports declare a tool surface; changes need a tool-use readiness check.", "command": "agents-shipgate detect --workspace . --json" }, { "id": "TRIGGER-OPENAPI-SPEC-CHANGED", "agents_md_row": "Adds/changes MCP exports, OpenAPI specs, or `tools/*openai*tools*.json`", "when": { "any_of": [ {"glob": "**/*openapi*.yaml"}, {"glob": "**/*openapi*.yml"}, {"glob": "**/*openapi*.json"}, {"glob": "**/*swagger*.yaml"}, {"glob": "**/*swagger*.yml"}, {"glob": "**/*swagger*.json"} ] }, "action": "run_shipgate", "rationale": "OpenAPI specs define HTTP-tool surfaces; scope coverage and side-effect classification depend on them.", "command": "agents-shipgate detect --workspace . --json" }, { "id": "TRIGGER-STATIC-TOOL-INVENTORY-CHANGED", "agents_md_row": "Adds/changes MCP exports, OpenAPI specs, or `tools/*openai*tools*.json`", "when": { "any_of": [ {"glob": "tools/*openai*tools*.json"}, {"glob": "tools/*anthropic*tools*.json"}, {"glob": "tools/anthropic-tools.json"} ] }, "action": "run_shipgate", "rationale": "Static tool inventories for the OpenAI and Anthropic Messages APIs are first-class tool sources." }, { "id": "TRIGGER-CODEX-PLUGIN-CHANGED", "agents_md_row": "Adds/changes Codex plugin manifests, marketplace files, `.app.json`, `.mcp.json`, or `SKILL.md` files", "when": { "any_of": [ {"glob": ".codex-plugin/**"}, {"glob": "**/.codex-plugin/**"}, {"glob": ".agents/plugins/**"}, {"glob": "**/.agents/plugins/**"}, {"glob": "**/.app.json"}, {"glob": "**/.mcp.json"}, {"glob": "**/SKILL.md"} ] }, "action": "run_shipgate", "rationale": "Codex plugin packages and marketplaces are static release surfaces; plugin metadata, skills, apps, MCP server declarations, and hooks need a readiness check.", "command": "agents-shipgate detect --workspace . --json" }, { "id": "TRIGGER-N8N-WORKFLOW-CHANGED", "agents_md_row": "Adds/changes n8n workflow JSON, credential stubs, or n8n tool inventories", "when": { "any_of": [ {"diff_contains": "n8n-nodes-base."}, {"diff_contains": "n8n-nodes-langchain."}, {"diff_contains": "@n8n/n8n-nodes-"}, {"glob": "**/*n8n*.json"}, {"glob": "**/.n8n/**"} ] }, "action": "run_shipgate", "rationale": "n8n workflow JSON declares an AI tool surface (AI Agent tool sub-nodes, MCP client/server tools, HTTP Request tools); `n8n-nodes-*` node-type tokens are the stable in-diff marker. Changes need a tool-use readiness check." }, { "id": "TRIGGER-FUNCTION-TOOL-DECORATOR", "agents_md_row": "Adds/changes `@function_tool`/`@tool` decorators (LangChain, CrewAI, OpenAI Agents SDK)", "when": { "any_of": [ {"diff_contains": "@function_tool"}, {"diff_contains": "@tool"}, {"diff_contains": "FunctionTool("} ] }, "action": "run_shipgate", "rationale": "`@function_tool` / `@tool` (LangChain, CrewAI, OpenAI Agents SDK) and ADK `FunctionTool(...)` add or modify the tools the agent can call." }, { "id": "TRIGGER-PROMPTS-OR-POLICIES", "agents_md_row": "Edits `prompts/`, `policies/`, or `permissions.scopes` in `shipgate.yaml`", "when": { "any_of": [ {"glob": "prompts/**"}, {"glob": "policies/**"} ] }, "action": "run_shipgate", "rationale": "Prompts and policy YAML carry approval / confirmation evidence. Trace findings reference these surfaces." }, { "id": "TRIGGER-SHIPGATE-MANIFEST", "agents_md_row": "Edits `prompts/`, `policies/`, or `permissions.scopes` in `shipgate.yaml`", "when": {"glob": "shipgate.yaml"}, "action": "run_shipgate", "rationale": "The manifest is the source of truth for the release gate." }, { "id": "TRIGGER-SHIPGATE-CI-WORKFLOW", "agents_md_row": "Adds/edits `.github/workflows/agents-shipgate.yml` or related CI", "when": { "any_of": [ {"glob": ".github/workflows/agents-shipgate.yml"}, {"glob": ".github/workflows/agents-shipgate.yaml"}, {"diff_contains": "ThreeMoonsLab/agents-shipgate"} ] }, "action": "run_shipgate", "rationale": "CI gate changes touch the release-readiness path itself." }, { "id": "TRIGGER-EXISTING-MANIFEST-PRESENT", "agents_md_row": "Repo already opted in (shipgate.yaml present in the workspace)", "when": {"file_present": "shipgate.yaml"}, "action": "force_run", "rationale": "Repo already opted in; run on every PR — including docs-only — because the manifest's existence is the operational opt-in. `force_run` overrides any `skip_shipgate` rule that would otherwise fire (e.g. a docs-only PR in an opted-in repo)." }, { "id": "TRIGGER-FRAMEWORK-VERSION-BUMP", "agents_md_row": "(Optional) Refactor or framework upgrade that may shift the extracted tool surface", "when": { "any_of": [ {"diff_contains": "openai-agents"}, {"diff_contains": "langchain"}, {"diff_contains": "crewai"}, {"diff_contains": "google-adk"} ] }, "action": "dry_run", "rationale": "Framework dependency bumps can shift the extracted tool surface; dry-run is a defensive no-cost check." }, { "id": "TRIGGER-DOCS-ONLY-NEGATIVE", "agents_md_row": "Pure read-only doc/test changes with no manifest impact", "when": { "all_of": [ {"every_file_matches": [ "**/*.md", "tests/**", "test/**", "**/tests/**", "**/test/**", "**/test_*.py", "**/*_test.py", "**/conftest.py" ]}, {"none_match_glob": [ "shipgate.yaml", "**/*tools*.json", "**/*mcp*.json", ".codex-plugin/**", "**/.codex-plugin/**", ".agents/plugins/**", "**/.agents/plugins/**", "**/.app.json", "**/.mcp.json", "**/SKILL.md", "**/*openapi*.yaml", "**/*openapi*.yml", "**/*openapi*.json", "prompts/**", "policies/**" ]} ] }, "action": "skip_shipgate", "rationale": "Docs-only OR tests-only PR; no tool surface impact. Covers the AGENTS.md row 'Pure read-only doc/test changes' — a tests/ directory edit that incidentally mentions `@tool` in a fixture or assertion no longer falsely triggers Shipgate." } ], "stop_conditions": { "description": "Stop and do not propose Shipgate when ALL of these hold (mirrors AGENTS.md \"Stop conditions\" prose).", "all_of": [ {"detect_returns": "is_agent_project: false"}, {"detect_returns": "suggested_sources: []"}, {"detect_returns": "codex_plugin_candidates: []"}, {"file_absent": "shipgate.yaml"}, {"user_did_not_request": true} ] }, "actions": { "force_run": "Propose Shipgate unconditionally. Overrides `skip_shipgate` rules — used when the repo has explicitly opted in (e.g. existing `shipgate.yaml`) and every PR should be checked.", "run_shipgate": "Propose `agents-shipgate detect --json` as the next step; if `is_agent_project` or `suggested_sources` is non-trivial, follow with `init --write --ci` and `scan`. Does NOT win over `skip_shipgate` — a docs-only PR that incidentally mentions a tool decorator stays skipped.", "skip_shipgate": "Do not propose Shipgate. Beats `run_shipgate` (but loses to `force_run`). Recommend other appropriate checks for the PR.", "dry_run": "Advisory: `run_shipgate` stays false but `dry_run_recommended` is true in the evaluator output. Callers may propose a non-mutating scan; never propose `init --write` based on `dry_run` alone." }, "action_precedence": [ "stop_conditions (block everything)", "force_run (overrides skip)", "skip_shipgate (overrides run)", "run_shipgate", "dry_run (sets dry_run_recommended; run_shipgate stays false)", "no rules matched (skip)" ] }