{"id":31684558,"url":"https://github.com/flowcore-io/usable-pr-validator","last_synced_at":"2026-04-26T18:00:29.755Z","repository":{"id":318321961,"uuid":"1070785554","full_name":"flowcore-io/usable-pr-validator","owner":"flowcore-io","description":"Usable PR Validator - Validate Pull Requests against your Usable knowledge base standards using Google Gemini AI","archived":false,"fork":false,"pushed_at":"2026-04-15T11:44:43.000Z","size":432,"stargazers_count":2,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-15T13:40:15.879Z","etag":null,"topics":["ai","automation","code-review","gemini","github-actions","knowledge-base","mcp","pr-validation","usable"],"latest_commit_sha":null,"homepage":null,"language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/flowcore-io.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2025-10-06T12:43:41.000Z","updated_at":"2026-04-15T11:44:30.000Z","dependencies_parsed_at":"2025-10-06T15:08:30.210Z","dependency_job_id":"0be166f1-5878-4f92-bff8-147a3efe7cb9","html_url":"https://github.com/flowcore-io/usable-pr-validator","commit_stats":null,"previous_names":["flowcore-io/usable-pr-validator"],"tags_count":19,"template":false,"template_full_name":null,"purl":"pkg:github/flowcore-io/usable-pr-validator","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flowcore-io%2Fusable-pr-validator","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flowcore-io%2Fusable-pr-validator/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flowcore-io%2Fusable-pr-validator/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flowcore-io%2Fusable-pr-validator/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/flowcore-io","download_url":"https://codeload.github.com/flowcore-io/usable-pr-validator/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flowcore-io%2Fusable-pr-validator/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32307015,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-26T17:23:19.671Z","status":"ssl_error","status_checked_at":"2026-04-26T17:23:19.195Z","response_time":129,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai","automation","code-review","gemini","github-actions","knowledge-base","mcp","pr-validation","usable"],"created_at":"2025-10-08T08:09:57.284Z","updated_at":"2026-04-26T18:00:29.719Z","avatar_url":"https://github.com/flowcore-io.png","language":"Shell","readme":"# 🤖 Usable PR Validator\n\n\u003e Validate Pull Requests against your Usable knowledge base standards using AI (OpenCode with OpenRouter, Anthropic, OpenAI, or Google Gemini)\n\n[![GitHub Marketplace](https://img.shields.io/badge/Marketplace-Usable%20PR%20Validator-blue?logo=github)](https://github.com/marketplace/actions/usable-pr-validator)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n[![Powered by Usable](https://img.shields.io/badge/Powered%20by-Usable-6366f1)](https://usable.dev)\n\n## ✨ Features\n\n- 🧠 **AI-Powered Validation**: Uses OpenCode with OpenRouter (default), Anthropic, OpenAI, or Google Gemini to understand context and architectural patterns\n- 🔀 **Multi-Provider Support**: Choose between OpenRouter (75+ models), Anthropic, OpenAI, or Google Gemini\n- 📚 **Usable Integration**: Validate PRs against your team's knowledge base stored in Usable\n- 🔌 **MCP Protocol**: Connects directly to Usable's MCP server for real-time standards\n- 🎯 **System Prompts**: Organization-wide validation standards fetched from Usable and auto-merged\n- 🚀 **Dynamic Prompts**: Fetch latest validation prompts from Usable API (no static files needed!)\n- 💬 **Comment-Triggered Revalidation**: Mention `@usable` in PR comments to trigger revalidation with context\n- 📝 **Automatic Deviation Documentation**: AI creates knowledge base fragments when deviations are approved\n- ⚙️ **Highly Configurable**: Customizable prompts, severity levels, and validation rules\n- 🔄 **Reliable**: Automatic retry logic with exponential backoff for API failures\n- 💬 **Smart PR Comments**: Updates existing comments to avoid spam\n- 📊 **Detailed Reports**: Structured validation reports as artifacts and PR comments\n- 🔒 **Secure**: Proper secret handling with automatic cleanup\n\n## 🚀 Quick Start (5 Minutes)\n\n### Prerequisites\n\n**For OpenCode (default, supports OpenRouter, Anthropic, OpenAI):**\n1. An API key for your chosen provider (e.g., [OpenRouter](https://openrouter.ai/settings/keys), [Anthropic](https://console.anthropic.com/), or [OpenAI](https://platform.openai.com/))\n2. A Usable account with API token ([get one at usable.dev](https://usable.dev))\n3. GitHub repository with pull requests\n\n**For Google Gemini (alternative provider):**\n1. A Google Cloud project with Vertex AI API enabled\n2. A service account key with Vertex AI permissions\n3. A Usable account with API token ([get one at usable.dev](https://usable.dev))\n4. GitHub repository with pull requests\n\n### Choosing a Provider\n\nProvider selection works in two levels:\n\n1. **`provider`** chooses the CLI tool: `opencode` (default) or `gemini`\n2. **`opencode-provider`** chooses which AI service OpenCode connects to (only applies when `provider` is `opencode`)\n\n```\nprovider\n├── opencode (default)\n│   └── opencode-provider\n│       ├── openrouter (default) ─ 75+ models via OpenRouter\n│       ├── anthropic             ─ Claude models direct\n│       └── openai                ─ GPT models direct\n└── gemini\n    └── Uses Google Gemini directly (configured via gemini-model)\n```\n\n### Step 1: Create Validation Prompt\n\nCreate `.github/prompts/pr-validation.md` in your repository:\n\n```markdown\n# PR Validation Instructions\n\n## CRITICAL OUTPUT INSTRUCTION\n**START YOUR OUTPUT DIRECTLY WITH:** `# PR Validation Report`\n\n## PR Context\n{{PR_CONTEXT}}\n\n## Your Task\nAnalyze the changes and validate against standards.\n\n### Get PR Changes\n```bash\ngit diff origin/{{BASE_BRANCH}}...{{HEAD_BRANCH}}\n```\n\n[See templates/ directory for complete examples]\n\n### Step 2: Add GitHub Secrets\n\nGo to your repository Settings → Secrets → Actions and add:\n\n**For OpenCode (default):**\n- `OPENCODE_API_KEY`: Your AI provider API key (e.g., [OpenRouter](https://openrouter.ai/settings/keys), [Anthropic](https://console.anthropic.com/), or [OpenAI](https://platform.openai.com/))\n- `USABLE_API_TOKEN`: Your Usable API token (get from [usable.dev](https://usable.dev) → Settings → API Tokens)\n\n\u003e If using a non-default provider, also set `opencode-provider` and `opencode-model` in your workflow:\n\u003e\n\u003e | Provider | `opencode-provider` | `opencode-model` example |\n\u003e |----------|--------------------|-----------------------|\n\u003e | OpenRouter (default) | `openrouter` | `moonshotai/kimi-k2.5` |\n\u003e | Anthropic | `anthropic` | `claude-sonnet-4-5` |\n\u003e | OpenAI | `openai` | `gpt-4o` |\n\n**For Gemini (alternative):**\n- `GEMINI_SERVICE_ACCOUNT_KEY`: Base64-encoded service account JSON key\n\n  ```bash\n  cat service-account.json | base64\n  ```\n\n- `USABLE_API_TOKEN`: Your Usable API token (get from [usable.dev](https://usable.dev) → Settings → API Tokens)\n\n### Step 3: Create Workflow\n\nCreate `.github/workflows/pr-validation.yml`:\n\n```yaml\nname: PR Validation\n\non:\n  pull_request:\n    branches: [main, develop]\n\npermissions:\n  contents: read\n  pull-requests: write\n\njobs:\n  validate:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          fetch-depth: 0\n\n      - uses: flowcore/usable-pr-validator@latest\n        with:\n          prompt-file: '.github/prompts/pr-validation.md'\n          workspace-id: 'your-workspace-uuid'\n        env:\n          OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }}\n          USABLE_API_TOKEN: ${{ secrets.USABLE_API_TOKEN }}\n```\n\nThat's it! Your PRs will now be validated automatically. 🎉\n\n## 📖 Configuration\n\n### Inputs\n\n| Input | Description | Required | Default |\n|-------|-------------|----------|---------|\n| `prompt-file` | Path to validation prompt markdown file (optional if `use-dynamic-prompts` is enabled) | | |\n| `use-dynamic-prompts` | Fetch latest prompt from Usable API instead of using static file | | `false` |\n| `prompt-fragment-id` | Usable fragment UUID to use as prompt (required when `use-dynamic-prompts` is `true`) | ✓ (with dynamic prompts) | |\n| `workspace-id` | Usable workspace UUID (required - used to fetch MCP system prompt) | ✓ | |\n| `merge-custom-prompt` | Merge fetched Usable prompt with custom `prompt-file` (only when both are provided) | | `true` |\n| `provider` | AI provider to use (`opencode` or `gemini`) | | `opencode` |\n| `opencode-provider` | AI provider for OpenCode (e.g., `openrouter`, `anthropic`, `openai`) | | `openrouter` |\n| `opencode-model` | Model ID for OpenCode | | `moonshotai/kimi-k2.5` |\n| `opencode-api-key-secret` | Secret name for the configured opencode-provider API key | | `OPENCODE_API_KEY` |\n| `gemini-model` | Gemini model to use (when provider is `gemini`) | | `gemini-2.5-flash` |\n| `service-account-key-secret` | Secret name for Gemini service account key | | `GEMINI_SERVICE_ACCOUNT_KEY` |\n| `mcp-server-url` | Usable MCP server URL | | `https://usable.dev/api/mcp` |\n| `mcp-token-secret` | Secret name for Usable API token | | `USABLE_API_TOKEN` |\n| `fail-on-critical` | Fail build on critical violations | | `true` |\n| `comment-mode` | PR comment behavior (`update`/`new`/`none`) | | `update` |\n| `comment-title` | Title for PR comment (for multi-stage validation) | | `Automated Standards Validation` |\n| `artifact-retention-days` | Days to retain reports | | `30` |\n| `max-retries` | Maximum retry attempts | | `2` |\n| `timeout-minutes` | Maximum execution time in minutes | | `15` |\n| `base-ref` | Base reference for diff comparison. Useful for release-please branches to compare against last release tag instead of base branch. | | PR base branch |\n| `head-ref` | Head reference for diff comparison | | PR head branch |\n| `allow-web-fetch` | Allow AI to use web_fetch tool for external resources (security consideration) | | `false` |\n\n\u003e **Note**: You must set the `USABLE_API_TOKEN` secret and either `OPENCODE_API_KEY` (default provider) or `GEMINI_SERVICE_ACCOUNT_KEY` (gemini provider). Usable MCP integration is required for this action.\n\n### 🧠 System Prompts (Automatic)\n\nThe action **automatically** includes system prompts to ensure high-quality validations. The final prompt is assembled in this order:\n\n1. **Action System Prompt** (hardcoded in `system-prompt.md`)\n   - Critical guidelines (no hallucination, verify file contents)\n   - Output format requirements\n   - Severity definitions\n   - Usable MCP integration instructions\n\n2. **Workspace MCP System Prompt** (fetched from Usable API)\n   - Your workspace-specific Usable MCP guidelines\n   - Fetched from `/api/workspaces/{workspace-id}/mcp-system-prompt`\n   - Defines how to search and use your knowledge base\n\n3. **User Prompt** (your validation rules)\n   - Repository-specific validation criteria\n   - Can be a static file or dynamic from Usable\n\nThis three-layer approach ensures:\n\n- ✅ Consistent validation behavior across all repositories\n- ✅ Proper Usable MCP integration\n- ✅ Accurate, hallucination-free reports\n- ✅ Flexibility for repo-specific rules\n\n### 📋 Smart Diff Summary (Efficient Validation)\n\nThe action provides the AI with a **compact summary** of changed files rather than dumping massive diffs into the prompt. This makes validation more reliable, scalable, and cost-effective.\n\n**What the AI Receives:**\n\n```markdown\n## 📋 Changed Files Summary\n\n**Total files changed**: 15\n\n### `src/app/api/users/route.ts`\n- **Changes**: +45 lines, -12 lines\n- **Modified ranges**: Line 10-25, Line 45-67, Line 89-102\n\n### `src/lib/services/user.service.ts`\n- **Changes**: +23 lines, -8 lines\n- **Modified ranges**: Line 15-30, Line 55-61\n```\n\n**How the AI Uses It:**\n\n1. **Reviews the summary** to understand scope and which files changed\n2. **Reads specific files** on-demand using `cat` or `git show HEAD:path/to/file.ts`\n3. **Focuses on modified line ranges** mentioned in the summary\n4. **Checks dependencies** when needed (imports, configs, related files)\n5. **Validates intelligently** without needing to process full diffs\n\n**Benefits:**\n\n- ✅ **Scalable**: Works with PRs of any size (even 100+ files)\n- ✅ **Reliable**: AI doesn't need to run `git diff` (which can fail)\n- ✅ **Efficient**: Reads only what it needs, not entire file contents upfront\n- ✅ **Cost-effective**: Smaller prompt sizes = lower API costs\n- ✅ **Intelligent**: Agentic approach lets the AI decide what to fetch\n\n**Example Validation Flow:**\n\n```text\nSummary shows: src/app/api/subscription/route.ts changed (lines 10-25)\n\nAI's approach:\n1. cat src/app/api/subscription/route.ts          # Read the changed file\n2. Focus on lines 10-25                            # That's what changed\n3. cat src/lib/services/subscription.service.ts   # Check the imported service\n4. grep \"subscription-updated\" flowcore.yml       # Verify event type exists\n5. Report any violations found\n```\n\nThis agent-driven approach is more robust than trying to inject massive git diffs into the prompt, especially for large PRs where diffs can exceed token limits.\n\n### 🚀 Dynamic Prompts\n\nInstead of maintaining static prompt files, you can now fetch prompts dynamically from your Usable workspace. This ensures you're always using the latest validation standards without manual updates.\n\n**Benefits:**\n\n- ✅ Always use the latest validation best practices\n- ✅ Reduced setup complexity - no prompt file needed\n- ✅ Automatic updates when your team's standards evolve\n- ✅ Centralized prompt management in Usable\n\n**How it works:**\n\n1. Enable `use-dynamic-prompts: true`\n2. Provide the `prompt-fragment-id` with your Usable fragment UUID\n3. The action fetches that specific prompt from your Usable workspace\n4. Automatically merges with system prompts (action + MCP)\n\n**Examples:**\n\n```yaml\n# Dynamic user prompt from Usable\n- uses: flowcore/usable-pr-validator@latest\n  with:\n    use-dynamic-prompts: true\n    prompt-fragment-id: 'user-prompt-uuid'\n    workspace-id: 'your-workspace-uuid'\n  env:\n    OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }}\n    USABLE_API_TOKEN: ${{ secrets.USABLE_API_TOKEN }}\n\n# Static user prompt file (most common)\n- uses: flowcore/usable-pr-validator@latest\n  with:\n    prompt-file: '.github/prompts/pr-validation.md'\n    workspace-id: 'your-workspace-uuid'\n  env:\n    OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }}\n    USABLE_API_TOKEN: ${{ secrets.USABLE_API_TOKEN }}\n```\n\n### Outputs\n\n| Output | Description |\n|--------|-------------|\n| `validation-status` | Result: `passed` or `failed` |\n| `validation-passed` | Boolean: `true` or `false` |\n| `critical-issues` | Count of critical violations |\n| `report-artifact-name` | Name of report artifact |\n\n## 🎯 Usage Examples\n\n### Minimal Setup (OpenCode - default)\n\n```yaml\n- uses: flowcore/usable-pr-validator@latest\n  with:\n    prompt-file: '.github/prompts/validate.md'\n    workspace-id: 'your-workspace-uuid'\n  env:\n    OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }}\n    USABLE_API_TOKEN: ${{ secrets.USABLE_API_TOKEN }}\n```\n\n### Using Gemini Instead\n\n```yaml\n- uses: flowcore/usable-pr-validator@latest\n  with:\n    prompt-file: '.github/prompts/validate.md'\n    workspace-id: 'your-workspace-uuid'\n    provider: 'gemini'\n  env:\n    GEMINI_SERVICE_ACCOUNT_KEY: ${{ secrets.GEMINI_SERVICE_ACCOUNT_KEY }}\n    USABLE_API_TOKEN: ${{ secrets.USABLE_API_TOKEN }}\n```\n\n### With Custom MCP Server\n\n```yaml\n- uses: flowcore/usable-pr-validator@latest\n  with:\n    prompt-file: '.github/prompts/validate.md'\n    workspace-id: 'your-workspace-uuid'\n    mcp-server-url: 'https://your-custom-mcp.com/api/mcp'\n    mcp-token-secret: 'YOUR_CUSTOM_TOKEN'\n  env:\n    OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }}\n    YOUR_CUSTOM_TOKEN: ${{ secrets.YOUR_MCP_TOKEN }}\n```\n\n### Advanced Configuration\n\n```yaml\n- uses: flowcore/usable-pr-validator@latest\n  with:\n    prompt-file: '.github/validation/standards.md'\n    workspace-id: 'your-workspace-uuid'\n    provider: 'opencode'\n    opencode-provider: 'anthropic'\n    opencode-model: 'claude-sonnet-4-5'\n    mcp-server-url: 'https://confluence.company.com/api/mcp'\n    mcp-token-secret: 'CONFLUENCE_TOKEN'\n    fail-on-critical: true\n    comment-mode: 'update'\n    artifact-retention-days: 90\n    max-retries: 3\n  env:\n    OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }}\n    CONFLUENCE_TOKEN: ${{ secrets.CONF_API_TOKEN }}\n```\n\n### Multiple Validation Stages\n\nUse `comment-title` to create separate PR comments for each validation stage:\n\n```yaml\njobs:\n  validate-backend:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          fetch-depth: 0\n      \n      - uses: flowcore/usable-pr-validator@latest\n        with:\n          prompt-file: '.github/prompts/backend-standards.md'\n          workspace-id: 'your-workspace-uuid'\n          comment-title: 'Backend Validation'  # Creates unique comment\n        env:\n          OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }}\n          USABLE_API_TOKEN: ${{ secrets.USABLE_API_TOKEN }}\n\n  validate-frontend:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          fetch-depth: 0\n      \n      - uses: flowcore/usable-pr-validator@latest\n        with:\n          prompt-file: '.github/prompts/frontend-standards.md'\n          workspace-id: 'your-workspace-uuid'\n          comment-title: 'Frontend Validation'  # Creates unique comment\n        env:\n          OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }}\n          USABLE_API_TOKEN: ${{ secrets.USABLE_API_TOKEN }}\n```\n\n\u003e **Note**: Each `comment-title` creates a separate PR comment that updates independently. Artifacts are also uniquely named based on the title.\n\n### Release-Please Integration\n\nValidate all changes since the last release for release-please PRs:\n\n```yaml\nname: PR Validation\n\non:\n  pull_request:\n    branches: [main]\n\njobs:\n  validate:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          fetch-depth: 0\n      \n      # Determine base reference for release-please branches\n      - name: Get base reference\n        id: base-ref\n        run: |\n          if [[ \"${{ github.head_ref }}\" == release-please--* ]]; then\n            # For release-please branches, compare against last release tag\n            LAST_TAG=$(git describe --tags --abbrev=0 2\u003e/dev/null || echo \"${{ github.event.pull_request.base.ref }}\")\n            echo \"ref=${LAST_TAG}\" \u003e\u003e $GITHUB_OUTPUT\n            echo \"Comparing against last release: ${LAST_TAG}\"\n          else\n            # For regular PRs, use base branch\n            echo \"ref=${{ github.event.pull_request.base.ref }}\" \u003e\u003e $GITHUB_OUTPUT\n            echo \"Comparing against base branch: ${{ github.event.pull_request.base.ref }}\"\n          fi\n      \n      - uses: flowcore/usable-pr-validator@latest\n        with:\n          prompt-file: '.github/prompts/pr-validation.md'\n          workspace-id: 'your-workspace-uuid'\n          base-ref: ${{ steps.base-ref.outputs.ref }}  # Custom base reference\n        env:\n          OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }}\n          USABLE_API_TOKEN: ${{ secrets.USABLE_API_TOKEN }}\n```\n\n\u003e **Tip**: This ensures release-please PRs validate all accumulated changes since the previous release, not just the most recent commit.\n\n## 📝 Prompt Engineering\n\n### Best Practices\n\n1. **Clear Output Format**: Always specify exact markdown structure\n2. **Suppress Preamble**: Explicitly instruct to start with report header\n3. **Context Limits**: Remind AI not to output fetched content or logs\n4. **Severity Levels**: Define clear criteria for Critical/Important/Suggestion\n5. **Examples**: Include good/bad patterns in prompt\n\n### Placeholder Variables\n\nAvailable in your prompt file:\n\n- `{{PR_CONTEXT}}` - Full PR context (number, title, description, URL)\n- `{{BASE_BRANCH}}` - Target branch (e.g., `main`)\n- `{{HEAD_BRANCH}}` - Source branch (e.g., `feature/new-thing`)\n- `{{PR_TITLE}}` - Just the PR title\n- `{{PR_DESCRIPTION}}` - Just the PR description\n- `{{PR_NUMBER}}` - Just the PR number\n- `{{PR_URL}}` - Direct link to PR\n- `{{PR_AUTHOR}}` - GitHub username\n- `{{PR_LABELS}}` - Comma-separated labels\n\n### Report Structure\n\nYour prompt should instruct the AI to output this structure:\n\n```markdown\n# PR Validation Report\n\n## Summary\n[Brief overview of findings]\n\n## Critical Violations ❌\n[Must-fix issues - build fails if present]\n\n## Important Issues ⚠️\n[Should-fix issues - build passes but flagged]\n\n## Suggestions ℹ️\n[Nice-to-have improvements]\n\n## Validation Outcome\n- **Status**: PASS ✅ | FAIL ❌\n- **Critical Issues**: [count]\n- **Important Issues**: [count]\n- **Suggestions**: [count]\n```\n\n## 🔌 Usable Integration (Required)\n\n### What is Usable?\n\nUsable is a team knowledge base and memory system that stores your:\n\n- Coding standards and conventions\n- Architecture patterns and decisions\n- Security requirements and best practices\n- Project-specific documentation\n\n**This action requires Usable** and connects to your Usable workspace via MCP (Model Context Protocol) to validate PRs against your living documentation. The integration is always enabled and provides the AI with access to your team's knowledge base.\n\n### Setup\n\n1. **Get Your Usable API Token**\n   - Go to [usable.dev](https://usable.dev)\n   - Navigate to Settings → API Tokens\n   - Create a new token with `fragments.read` permission\n\n2. **Add GitHub Secrets**\n\n   ```bash\n   # In your repo: Settings → Secrets → Actions\n   USABLE_API_TOKEN=your_usable_token_here\n   OPENCODE_API_KEY=your_api_key_here\n   ```\n\n3. **Configure Workflow**\n\n  ```yaml\n  - uses: flowcore/usable-pr-validator@latest\n    with:\n      prompt-file: '.github/prompts/pr-validation.md'\n      workspace-id: 'your-workspace-uuid'\n    env:\n      OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }}\n      USABLE_API_TOKEN: ${{ secrets.USABLE_API_TOKEN }}\n  ```\n\n   \u003e **Note**: Usable MCP integration is always enabled and uses `https://usable.dev/api/mcp` by default. You can customize the server URL with the `mcp-server-url` input if needed.\n\n1. **Update Prompt to Use Usable**\n\n   ```markdown\n   ### Fetch Standards from Usable\n   \n   Use agentic-search-fragments to find relevant standards:\n   - Coding standards for {{BASE_BRANCH}}\n   - Architecture patterns\n   - Security requirements\n   - repo:your-repo-name tag\n   \n   Use get-memory-fragment-content for full details.\n   ```\n\n## 💬 Comment-Triggered Revalidation\n\n**⚡ 2-Minute Setup** - Add comment-triggered validation to any repository!\n\n### @usable Mentions\n\nTrigger revalidations and approve deviations by commenting on a PR with `@usable`:\n\n```text\n@usable This PR intentionally uses console.log in debug utilities.\nThese files are specifically for debugging and need console output.\n```\n\n**What Happens**:\n\n1. ✅ The action automatically triggers a revalidation\n2. 📝 Your comment is passed to the AI validator\n3. 🧠 The AI can:\n   - **Understand the context** you've provided\n   - **Approve deviations** from standards\n   - **Document the decision** by creating a fragment in Usable\n   - **Link the fragment** in the validation report\n4. 📊 A new validation report is posted with the override applied\n\n### Setting Up Comment Revalidation\n\nCreate `.github/workflows/comment-revalidation.yml`:\n\n```yaml\nname: Comment Revalidation\n\non:\n  issue_comment:\n    types: [created]\n\njobs:\n  revalidate:\n    # Only run if comment is on a PR and mentions @usable\n    if: |\n      github.event.issue.pull_request \u0026\u0026\n      contains(github.event.comment.body, '@usable')\n    \n    # Use the reusable workflow - it handles everything!\n    uses: flowcore/usable-pr-validator/.github/workflows/comment-revalidation.yml@v1\n    with:\n      workspace-id: 'your-workspace-uuid'  # REQUIRED\n      prompt-file: '.github/prompts/pr-validation.md'  # Optional\n      # Customize as needed:\n      # use-dynamic-prompts: true\n      # prompt-fragment-id: 'fragment-uuid'\n      # provider: 'opencode'\n      # opencode-model: 'moonshotai/kimi-k2.5'\n      # comment-title: '🔄 Custom Title'\n      # fail-on-critical: false\n    secrets:\n      OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }}\n      USABLE_API_TOKEN: ${{ secrets.USABLE_API_TOKEN }}\n    permissions:\n      contents: read\n      pull-requests: write\n```\n\n**That's it!** Just 15 lines and you're done. The reusable workflow handles:\n\n- ✅ Extracting PR details\n- ✅ Checking out the correct commit\n- ✅ Determining base ref (branch vs tag)\n- ✅ Running validation with override context\n- ✅ Posting results as a comment\n- ✅ Adding reaction emoji to acknowledge\n\n\u003e **Tip**: Copy `templates/comment-revalidation-workflow.yml` for a ready-to-use template\n\n### How It Works\n\n#### Example: Approving a Deviation\n\n1. **PR has a violation**: Validator flags `console.log` usage\n\n2. **Developer comments**:\n\n   ```text\n   @usable This is intentional. The debug utility needs console output \n   for troubleshooting production issues. Only used in /debug/ directory.\n   ```\n\n3. **Validator understands and documents**:\n   - Creates a fragment in Usable titled \"Approved Deviation: console.log in debug utilities\"\n   - Includes justification, conditions, PR link, and approver\n   - Tags it as `deviation`, `approved`, `repo:your-repo`\n\n4. **Report shows**:\n\n   ```markdown\n   ## Override Applied\n   \n   A deviation from standards has been approved and documented:\n   \n   - **Deviation**: console.log usage in debug utilities\n   - **Justification**: Required for production troubleshooting\n   - **Documentation**: Fragment created - \"Approved Deviation: console.log in debug utilities\" (ID: abc-123)\n   - **Approved by**: @developer\n   \n   This deviation has been recorded in the knowledge base for future reference.\n   ```\n\n**Use Cases**:\n\n- ✅ **Approve Deviations**: \"This violation is acceptable because...\"\n- 🎯 **Focus Validation**: \"@usable Focus on security issues only\"\n- 💡 **Provide Context**: \"@usable This API change was approved by the architecture team\"\n- 🔄 **Re-run After Fixes**: \"@usable Please revalidate now that I've fixed the issues\"\n\n**Benefits**:\n\n- 📚 **Knowledge Base Grows**: Approved deviations are automatically documented\n- 🔗 **Traceability**: Every deviation links back to the approving PR and person\n- 🤝 **Team Communication**: Decisions are visible to everyone\n- 🚀 **No Manual Work**: AI handles documentation automatically\n\n## 🔒 Security\n\n### Secret Handling\n\n- Service account keys are base64-decoded to `/tmp` with `600` permissions\n- Temporary files automatically cleaned up in `always()` block\n- Never logged or exposed in outputs\n- Use GitHub encrypted secrets for storage\n\n### Permissions Required\n\n```yaml\npermissions:\n  contents: read        # Read repository code\n  pull-requests: write  # Post comments\n```\n\n### Security Best Practices\n\n1. Rotate API keys regularly (OpenRouter or Google Cloud)\n2. Use least-privilege service accounts (Gemini provider)\n3. Review validation prompts for sensitive data\n4. **Keep `allow-web-fetch` disabled** (default) unless you specifically need it\n5. Use GitHub encrypted secrets for all API keys\n\n### Web Fetch Security\n\nThe `allow-web-fetch` input controls whether the AI can download external resources during validation.\n\n**Default: `false` (DISABLED)** - Recommended for most use cases\n\n- ✅ **When to keep it disabled (default)**:\n  - Standard PR validation using only your codebase and Usable knowledge base\n  - Security-sensitive environments\n  - When you want to ensure validation is fully reproducible\n  - When you don't need external documentation or references\n\n- ⚠️ **When you might enable it**:\n  - Validating against external API documentation\n  - Checking compliance with published standards (e.g., OWASP, RFC specs)\n  - Verifying links in documentation PRs\n  - Fetching external schema definitions\n\n**Security implications when enabled**:\n\n- AI can make HTTP requests to arbitrary URLs\n- Could potentially expose internal URLs if mentioned in PR\n- May introduce non-deterministic validation results\n- Consider network egress policies and firewall rules\n\n**Example of enabling**:\n\n```yaml\n- uses: flowcore/usable-pr-validator@latest\n  with:\n    prompt-file: '.github/prompts/validate-api-docs.md'\n    allow-web-fetch: true  # Only enable when needed\n  env:\n    OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }}\n    USABLE_API_TOKEN: ${{ secrets.USABLE_API_TOKEN }}\n```\n\n## 🐛 Troubleshooting\n\n### No Output from AI CLI\n\n**Symptom**: GitHub Action runs but shows no AI output or errors\n\n**Possible Causes**:\n\n- AI CLI (OpenCode or Gemini) failing silently\n- Output buffering issues\n- Git diff failures preventing AI from analyzing changes\n\n**Solutions**:\n\n1. **Check the Git Diff Setup section** in action logs:\n\n```\n🔍 Verifying Git Diff Setup\n✅ Base ref available: origin/main\n✅ Head ref available: origin/feature-branch\n✅ Three-dot diff works: origin/main...origin/feature-branch\n```\n\n2. **Look for CLI output** in the logs:\n\n```\n🤖 Running OpenCode CLI\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\nModel: openrouter/moonshotai/kimi-k2.5\nPrompt size: XXXX bytes\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n```\n\n3. **Check for error details** in collapsed groups:\n\n- Look for \"❌ Error Details\" group\n- Check both STDERR and STDOUT output\n- Review exit codes\n\n4. **Verify git refs are properly fetched**:\n\n```yaml\n- uses: actions/checkout@v4\n  with:\n    fetch-depth: 0  # Important: fetch full history\n```\n\n5. **Use the diagnostic script locally**:\n\n```bash\n# Clone the repo and run\n./scripts/test-git-diff.sh main feature-branch\n```\n\n### Git Diff Not Working\n\n**Symptom**: Error messages like \"revisions or paths not found\" or AI reports inability to analyze changes\n\n**Root Cause**: Git refs not properly fetched in GitHub Actions environment\n\n**Automated Fix** (already implemented in v1.3.1+):\n\n- Enhanced git setup with retry logic for both base and head refs\n- Multiple ref format attempts (branch, tag, explicit refspec)\n- Pre-flight validation that tests git diff before AI starts\n\n**Manual Verification**:\n\n```bash\n# Run diagnostic script\n./scripts/test-git-diff.sh \u003cbase-branch\u003e \u003chead-branch\u003e\n\n# Expected output:\n# ✅ Base ref available: origin/main\n# ✅ Head ref available: origin/feature\n# ✅ Three-dot diff works\n# 📊 5 files changed\n```\n\n**Common Mistake - Detached HEAD**:\n\nIf you're checking out with a specific SHA, this creates a detached HEAD state that breaks diff operations:\n\n```yaml\n# ❌ WRONG - Creates detached HEAD\n- uses: actions/checkout@v4\n  with:\n    ref: ${{ github.event.pull_request.head.sha }}\n    fetch-depth: 0\n\n# ✅ CORRECT - Let checkout handle the ref automatically\n- uses: actions/checkout@v4\n  with:\n    fetch-depth: 0  # This is all you need for PRs\n```\n\n**If you MUST use a specific ref**:\n\n```yaml\n# Option 1: Don't specify ref for PR workflows\n- uses: actions/checkout@v4\n  with:\n    fetch-depth: 0\n\n# Option 2: Explicitly fetch both refs after checkout\n- uses: actions/checkout@v4\n  with:\n    ref: ${{ github.event.pull_request.head.sha }}\n    fetch-depth: 0\n\n- name: Fetch branch refs\n  run: |\n    git fetch origin ${{ github.event.pull_request.base.ref }}:refs/remotes/origin/${{ github.event.pull_request.base.ref }}\n    git fetch origin ${{ github.event.pull_request.head.ref }}:refs/remotes/origin/${{ github.event.pull_request.head.ref }}\n```\n\n### MCP Tools Not Available\n\n**Symptom**: Error messages like `Tool \"search_memory_fragments\" not found in registry` or AI sees wrong tools (`search_file_content`, `read_many_files` instead of Usable Memory tools)\n\n**Root Cause**: MCP server not receiving workspace-id context, so it returns generic tools instead of Usable-specific memory tools\n\n**Solution** (Fixed in v1.6.0+):\n\nThe action now automatically passes `workspace-id` to the MCP server via the `x-workspace-id` header. Ensure you're using the latest version:\n\n```yaml\n- uses: flowcore-io/usable-pr-validator@v1.6.0  # or @latest\n  with:\n    workspace-id: '60c10ca2-4115-4c1a-b6d7-04ac39fd3938'  # Required!\n```\n\n**If using older versions**, update to v1.6.0+ or manually verify:\n\n1. `workspace-id` input is provided in your workflow\n2. Action passes `WORKSPACE_ID` environment variable to MCP setup\n3. MCP settings include `x-workspace-id` header in configuration\n\n**Expected MCP tools** when working correctly:\n\n- `agentic-search-fragments`\n- `search-memory-fragments`\n- `get-memory-fragment-content`\n- `explore-workspace-graph`\n- `create-memory-fragment`\n- `update-memory-fragment`\n\n### Validation Fails Immediately\n\n**Symptom**: Action fails before running Gemini\n\n**Causes**:\n\n- Prompt file not found\n- Missing required secrets\n- Invalid MCP configuration\n\n**Solution**:\n\n```bash\n# Check prompt file exists\nls -la .github/prompts/\n\n# Verify secrets are set\n# Go to repo Settings → Secrets → Actions\n```\n\n### Report Not Extracted\n\n**Symptom**: Warning about report extraction\n\n**Cause**: AI didn't follow output format instructions\n\n**Solution**: Strengthen prompt instructions:\n\n```markdown\n## CRITICAL OUTPUT INSTRUCTION\n**YOU MUST START WITH:** `# PR Validation Report`\nDO NOT include thinking process or explanations!\n```\n\n### API Rate Limit Errors\n\n**Symptom**: 429 errors from AI API\n\n**Solution**:\n\n- Increase `max-retries` (automatic exponential backoff is built in)\n- For OpenRouter: check your rate limits at [openrouter.ai](https://openrouter.ai)\n- For Gemini: use Vertex AI (higher limits) and check Google Cloud quotas\n\n### MCP Connection Failures\n\n**Symptom**: Can't connect to MCP server\n\n**Solutions**:\n\n```yaml\n# 1. Verify URL is correct\nmcp-server-url: 'https://correct-url.com/api/mcp'\n\n# 2. Check token is valid\n# Ensure MCP_API_TOKEN secret is set\n\n# 3. Test connectivity\ncurl -H \"Authorization: Bearer $TOKEN\" $MCP_URL\n```\n\n## 📊 Cost Estimation\n\n### OpenRouter Pricing (default)\n\n| Model | Input (per 1M tokens) | Output (per 1M tokens) | Typical PR Cost |\n|-------|----------------------|----------------------|----------------|\n| moonshotai/kimi-k2.5 | $0.45 | $2.25 | $0.02-0.10 |\n| anthropic/claude-sonnet-4-5 | $3.00 | $15.00 | $0.15-0.75 |\n| openai/gpt-4o | $2.50 | $10.00 | $0.10-0.50 |\n\n**Estimate**: ~$0.02-0.10 per PR with moonshotai/kimi-k2.5 (default)\n\n### Google Gemini Pricing (Vertex AI)\n\n| Model | Input (per 1M tokens) | Output (per 1M tokens) | Typical PR Cost |\n|-------|----------------------|----------------------|----------------|\n| gemini-2.5-flash | $0.075 | $0.30 | $0.01-0.03 |\n| gemini-2.0-flash | $0.10 | $0.40 | $0.02-0.05 |\n| gemini-2.5-pro | $1.25 | $5.00 | $0.25-1.00 |\n\n**Estimate**: ~$0.01-0.05 per PR with gemini-2.5-flash\n\n### MCP Costs\n\nMCP server costs vary by provider:\n\n- **Usable**: Check pricing at usable.dev\n- **Self-hosted**: Server infrastructure costs\n- **Confluence**: Included in license\n\n## 🔖 Versioning\n\nThis action follows [Semantic Versioning](https://semver.org/) and uses automated releases via [release-please](https://github.com/google-github-actions/release-please-action).\n\n### Using Specific Versions\n\n```yaml\n# Latest stable release (recommended)\n- uses: flowcore/usable-pr-validator@latest\n\n# Specific version (pinned)\n- uses: flowcore/usable-pr-validator@v1.0.0\n\n# Latest commit on main (not recommended for production)\n- uses: flowcore/usable-pr-validator@main\n```\n\n### Version Strategy\n\n- **Major (v1.x.x → v2.x.x)**: Breaking changes requiring user action\n- **Minor (v1.0.x → v1.1.x)**: New features, backward compatible\n- **Patch (v1.0.0 → v1.0.1)**: Bug fixes, backward compatible\n\nWe recommend using `@latest` to automatically receive the newest stable release.\n\n## 🤝 Contributing\n\nContributions welcome! See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.\n\nAll commits must follow [Conventional Commits](https://www.conventionalcommits.org/) for automated releases:\n\n- `feat:` for new features\n- `fix:` for bug fixes\n- `docs:` for documentation\n- `feat!:` or `BREAKING CHANGE:` for breaking changes\n\n### Development Setup\n\n```bash\ngit clone https://github.com/flowcore/usable-pr-validator.git\ncd usable-pr-validator\n\n# Test locally (requires act)\nact pull_request -s OPENCODE_API_KEY=\"your-key-here\" -s USABLE_API_TOKEN=\"your-token\"\n```\n\n## 📜 License\n\nMIT License - see [LICENSE](LICENSE) for details.\n\n## 🙏 Acknowledgments\n\n- [OpenCode](https://opencode.ai) CLI for multi-provider AI capabilities\n- [OpenRouter](https://openrouter.ai) for unified model access\n- Google Gemini for AI capabilities\n- Model Context Protocol (MCP) community\n- GitHub Actions ecosystem\n\n## 📞 Support\n\n- 🐛 [Report a bug](https://github.com/flowcore/usable-pr-validator/issues)\n- 💡 [Request a feature](https://github.com/flowcore/usable-pr-validator/issues)\n- 💬 [Discussions](https://github.com/flowcore/usable-pr-validator/discussions)\n\nMade with ❤️ by [Flowcore](https://flowcore.io)\n\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fflowcore-io%2Fusable-pr-validator","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fflowcore-io%2Fusable-pr-validator","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fflowcore-io%2Fusable-pr-validator/lists"}