# Usable Pr Validator

> Usable PR Validator - Validate Pull Requests against your Usable knowledge base standards using Google Gemini AI

- **Type:** MCP server
- **Install:** `agentstack add mcp-flowcore-io-usable-pr-validator`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [flowcore-io](https://agentstack.voostack.com/s/flowcore-io)
- **Installs:** 0
- **Category:** [Developer Tools](https://agentstack.voostack.com/c/developer-tools)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [flowcore-io](https://github.com/flowcore-io)
- **Source:** https://github.com/flowcore-io/usable-pr-validator

## Install

```sh
agentstack add mcp-flowcore-io-usable-pr-validator
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# 🤖 Usable PR Validator

> Validate Pull Requests against your Usable knowledge base standards using AI (OpenCode with OpenRouter, Anthropic, OpenAI, or Google Gemini)

[](https://github.com/marketplace/actions/usable-pr-validator)
[](https://opensource.org/licenses/MIT)
[](https://usable.dev)

## ✨ Features

- 🧠 **AI-Powered Validation**: Uses OpenCode with OpenRouter (default), Anthropic, OpenAI, or Google Gemini to understand context and architectural patterns
- 🔀 **Multi-Provider Support**: Choose between OpenRouter (75+ models), Anthropic, OpenAI, or Google Gemini
- 📚 **Usable Integration**: Validate PRs against your team's knowledge base stored in Usable
- 🔌 **MCP Protocol**: Connects directly to Usable's MCP server for real-time standards
- 🎯 **System Prompts**: Organization-wide validation standards fetched from Usable and auto-merged
- 🚀 **Dynamic Prompts**: Fetch latest validation prompts from Usable API (no static files needed!)
- 💬 **Comment-Triggered Revalidation**: Mention `@usable` in PR comments to trigger revalidation with context
- 📝 **Automatic Deviation Documentation**: AI creates knowledge base fragments when deviations are approved
- ⚙️ **Highly Configurable**: Customizable prompts, severity levels, and validation rules
- 🔄 **Reliable**: Automatic retry logic with exponential backoff for API failures
- 💬 **Smart PR Comments**: Updates existing comments to avoid spam
- 📊 **Detailed Reports**: Structured validation reports as artifacts and PR comments
- 🔒 **Secure**: Proper secret handling with automatic cleanup

## 🚀 Quick Start (5 Minutes)

### Prerequisites

**For OpenCode (default, supports OpenRouter, Anthropic, OpenAI):**
1. 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/))
2. A Usable account with API token ([get one at usable.dev](https://usable.dev))
3. GitHub repository with pull requests

**For Google Gemini (alternative provider):**
1. A Google Cloud project with Vertex AI API enabled
2. A service account key with Vertex AI permissions
3. A Usable account with API token ([get one at usable.dev](https://usable.dev))
4. GitHub repository with pull requests

### Choosing a Provider

Provider selection works in two levels:

1. **`provider`** chooses the CLI tool: `opencode` (default) or `gemini`
2. **`opencode-provider`** chooses which AI service OpenCode connects to (only applies when `provider` is `opencode`)

```
provider
├── opencode (default)
│   └── opencode-provider
│       ├── openrouter (default) ─ 75+ models via OpenRouter
│       ├── anthropic             ─ Claude models direct
│       └── openai                ─ GPT models direct
└── gemini
    └── Uses Google Gemini directly (configured via gemini-model)
```

### Step 1: Create Validation Prompt

Create `.github/prompts/pr-validation.md` in your repository:

```markdown
# PR Validation Instructions

## CRITICAL OUTPUT INSTRUCTION
**START YOUR OUTPUT DIRECTLY WITH:** `# PR Validation Report`

## PR Context
{{PR_CONTEXT}}

## Your Task
Analyze the changes and validate against standards.

### Get PR Changes
```bash
git diff origin/{{BASE_BRANCH}}...{{HEAD_BRANCH}}
```

[See templates/ directory for complete examples]

### Step 2: Add GitHub Secrets

Go to your repository Settings → Secrets → Actions and add:

**For OpenCode (default):**
- `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/))
- `USABLE_API_TOKEN`: Your Usable API token (get from [usable.dev](https://usable.dev) → Settings → API Tokens)

> If using a non-default provider, also set `opencode-provider` and `opencode-model` in your workflow:
>
> | Provider | `opencode-provider` | `opencode-model` example |
> |----------|--------------------|-----------------------|
> | OpenRouter (default) | `openrouter` | `moonshotai/kimi-k2.5` |
> | Anthropic | `anthropic` | `claude-sonnet-4-5` |
> | OpenAI | `openai` | `gpt-4o` |

**For Gemini (alternative):**
- `GEMINI_SERVICE_ACCOUNT_KEY`: Base64-encoded service account JSON key

  ```bash
  cat service-account.json | base64
  ```

- `USABLE_API_TOKEN`: Your Usable API token (get from [usable.dev](https://usable.dev) → Settings → API Tokens)

### Step 3: Create Workflow

Create `.github/workflows/pr-validation.yml`:

```yaml
name: PR Validation

on:
  pull_request:
    branches: [main, develop]

permissions:
  contents: read
  pull-requests: write

jobs:
  validate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - uses: flowcore-io/usable-pr-validator@latest
        with:
          prompt-file: '.github/prompts/pr-validation.md'
          workspace-id: 'your-workspace-uuid'
        env:
          OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }}
          USABLE_API_TOKEN: ${{ secrets.USABLE_API_TOKEN }}
```

That's it! Your PRs will now be validated automatically. 🎉

## 📖 Configuration

### Inputs

| Input | Description | Required | Default |
|-------|-------------|----------|---------|
| `prompt-file` | Path to validation prompt markdown file (optional if `use-dynamic-prompts` is enabled) | | |
| `use-dynamic-prompts` | Fetch latest prompt from Usable API instead of using static file | | `false` |
| `prompt-fragment-id` | Usable fragment UUID to use as prompt (required when `use-dynamic-prompts` is `true`) | ✓ (with dynamic prompts) | |
| `workspace-id` | Usable workspace UUID (required - used to fetch MCP system prompt) | ✓ | |
| `merge-custom-prompt` | Merge fetched Usable prompt with custom `prompt-file` (only when both are provided) | | `true` |
| `provider` | AI provider to use (`opencode` or `gemini`) | | `opencode` |
| `opencode-provider` | AI provider for OpenCode (e.g., `openrouter`, `anthropic`, `openai`) | | `openrouter` |
| `opencode-model` | Model ID for OpenCode | | `moonshotai/kimi-k2.5` |
| `opencode-api-key-secret` | Secret name for the configured opencode-provider API key | | `OPENCODE_API_KEY` |
| `gemini-model` | Gemini model to use (when provider is `gemini`) | | `gemini-2.5-flash` |
| `service-account-key-secret` | Secret name for Gemini service account key | | `GEMINI_SERVICE_ACCOUNT_KEY` |
| `mcp-server-url` | Usable MCP server URL | | `https://usable.dev/api/mcp` |
| `mcp-token-secret` | Secret name for Usable API token | | `USABLE_API_TOKEN` |
| `fail-on-critical` | Fail build on critical violations | | `true` |
| `comment-mode` | PR comment behavior (`update`/`new`/`none`) | | `update` |
| `comment-title` | Title for PR comment (for multi-stage validation) | | `Automated Standards Validation` |
| `artifact-retention-days` | Days to retain reports | | `30` |
| `max-retries` | Maximum retry attempts | | `2` |
| `timeout-minutes` | Maximum execution time in minutes | | `15` |
| `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 |
| `head-ref` | Head reference for diff comparison | | PR head branch |
| `allow-web-fetch` | Allow AI to use web_fetch tool for external resources (security consideration) | | `false` |

> **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.

### 🧠 System Prompts (Automatic)

The action **automatically** includes system prompts to ensure high-quality validations. The final prompt is assembled in this order:

1. **Action System Prompt** (hardcoded in `system-prompt.md`)
   - Critical guidelines (no hallucination, verify file contents)
   - Output format requirements
   - Severity definitions
   - Usable MCP integration instructions

2. **Workspace MCP System Prompt** (fetched from Usable API)
   - Your workspace-specific Usable MCP guidelines
   - Fetched from `/api/workspaces/{workspace-id}/mcp-system-prompt`
   - Defines how to search and use your knowledge base

3. **User Prompt** (your validation rules)
   - Repository-specific validation criteria
   - Can be a static file or dynamic from Usable

This three-layer approach ensures:

- ✅ Consistent validation behavior across all repositories
- ✅ Proper Usable MCP integration
- ✅ Accurate, hallucination-free reports
- ✅ Flexibility for repo-specific rules

### 📋 Smart Diff Summary (Efficient Validation)

The 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.

**What the AI Receives:**

```markdown
## 📋 Changed Files Summary

**Total files changed**: 15

### `src/app/api/users/route.ts`
- **Changes**: +45 lines, -12 lines
- **Modified ranges**: Line 10-25, Line 45-67, Line 89-102

### `src/lib/services/user.service.ts`
- **Changes**: +23 lines, -8 lines
- **Modified ranges**: Line 15-30, Line 55-61
```

**How the AI Uses It:**

1. **Reviews the summary** to understand scope and which files changed
2. **Reads specific files** on-demand using `cat` or `git show HEAD:path/to/file.ts`
3. **Focuses on modified line ranges** mentioned in the summary
4. **Checks dependencies** when needed (imports, configs, related files)
5. **Validates intelligently** without needing to process full diffs

**Benefits:**

- ✅ **Scalable**: Works with PRs of any size (even 100+ files)
- ✅ **Reliable**: AI doesn't need to run `git diff` (which can fail)
- ✅ **Efficient**: Reads only what it needs, not entire file contents upfront
- ✅ **Cost-effective**: Smaller prompt sizes = lower API costs
- ✅ **Intelligent**: Agentic approach lets the AI decide what to fetch

**Example Validation Flow:**

```text
Summary shows: src/app/api/subscription/route.ts changed (lines 10-25)

AI's approach:
1. cat src/app/api/subscription/route.ts          # Read the changed file
2. Focus on lines 10-25                            # That's what changed
3. cat src/lib/services/subscription.service.ts   # Check the imported service
4. grep "subscription-updated" flowcore.yml       # Verify event type exists
5. Report any violations found
```

This 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.

### 🚀 Dynamic Prompts

Instead 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.

**Benefits:**

- ✅ Always use the latest validation best practices
- ✅ Reduced setup complexity - no prompt file needed
- ✅ Automatic updates when your team's standards evolve
- ✅ Centralized prompt management in Usable

**How it works:**

1. Enable `use-dynamic-prompts: true`
2. Provide the `prompt-fragment-id` with your Usable fragment UUID
3. The action fetches that specific prompt from your Usable workspace
4. Automatically merges with system prompts (action + MCP)

**Examples:**

```yaml
# Dynamic user prompt from Usable
- uses: flowcore-io/usable-pr-validator@latest
  with:
    use-dynamic-prompts: true
    prompt-fragment-id: 'user-prompt-uuid'
    workspace-id: 'your-workspace-uuid'
  env:
    OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }}
    USABLE_API_TOKEN: ${{ secrets.USABLE_API_TOKEN }}

# Static user prompt file (most common)
- uses: flowcore-io/usable-pr-validator@latest
  with:
    prompt-file: '.github/prompts/pr-validation.md'
    workspace-id: 'your-workspace-uuid'
  env:
    OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }}
    USABLE_API_TOKEN: ${{ secrets.USABLE_API_TOKEN }}
```

### Outputs

| Output | Description |
|--------|-------------|
| `validation-status` | Result: `passed` or `failed` |
| `validation-passed` | Boolean: `true` or `false` |
| `critical-issues` | Count of critical violations |
| `report-artifact-name` | Name of report artifact |

## 🎯 Usage Examples

### Minimal Setup (OpenCode - default)

```yaml
- uses: flowcore-io/usable-pr-validator@latest
  with:
    prompt-file: '.github/prompts/validate.md'
    workspace-id: 'your-workspace-uuid'
  env:
    OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }}
    USABLE_API_TOKEN: ${{ secrets.USABLE_API_TOKEN }}
```

### Using Gemini Instead

```yaml
- uses: flowcore-io/usable-pr-validator@latest
  with:
    prompt-file: '.github/prompts/validate.md'
    workspace-id: 'your-workspace-uuid'
    provider: 'gemini'
  env:
    GEMINI_SERVICE_ACCOUNT_KEY: ${{ secrets.GEMINI_SERVICE_ACCOUNT_KEY }}
    USABLE_API_TOKEN: ${{ secrets.USABLE_API_TOKEN }}
```

### With Custom MCP Server

```yaml
- uses: flowcore-io/usable-pr-validator@latest
  with:
    prompt-file: '.github/prompts/validate.md'
    workspace-id: 'your-workspace-uuid'
    mcp-server-url: 'https://your-custom-mcp.com/api/mcp'
    mcp-token-secret: 'YOUR_CUSTOM_TOKEN'
  env:
    OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }}
    YOUR_CUSTOM_TOKEN: ${{ secrets.YOUR_MCP_TOKEN }}
```

### Advanced Configuration

```yaml
- uses: flowcore-io/usable-pr-validator@latest
  with:
    prompt-file: '.github/validation/standards.md'
    workspace-id: 'your-workspace-uuid'
    provider: 'opencode'
    opencode-provider: 'anthropic'
    opencode-model: 'claude-sonnet-4-5'
    mcp-server-url: 'https://confluence.company.com/api/mcp'
    mcp-token-secret: 'CONFLUENCE_TOKEN'
    fail-on-critical: true
    comment-mode: 'update'
    artifact-retention-days: 90
    max-retries: 3
  env:
    OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }}
    CONFLUENCE_TOKEN: ${{ secrets.CONF_API_TOKEN }}
```

### Multiple Validation Stages

Use `comment-title` to create separate PR comments for each validation stage:

```yaml
jobs:
  validate-backend:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      
      - uses: flowcore-io/usable-pr-validator@latest
        with:
          prompt-file: '.github/prompts/backend-standards.md'
          workspace-id: 'your-workspace-uuid'
          comment-title: 'Backend Validation'  # Creates unique comment
        env:
          OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }}
          USABLE_API_TOKEN: ${{ secrets.USABLE_API_TOKEN }}

  validate-frontend:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      
      - uses: flowcore-io/usable-pr-validator@latest
        with:
          prompt-file: '.github/prompts/frontend-standards.md'
          workspace-id: 'your-workspace-uuid'
          comment-title: 'Frontend Validation'  # Creates unique comment
        env:
          OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }}
          USABLE_API_TOKEN: ${{ secrets.USABLE_API_TOKEN }}
```

> **Note**: Each `comment-title` creates a separate PR comment that updates independently. Artifacts are also uniquely named based on the title.

### Release-Please Integration

Validate all changes since the last release for release-please PRs:

```yaml
name: PR Validation

on:
  pull_request:
    branches: [main]

jobs:
  validate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      
      # Determine base reference for release-please branches
      - name: Get base reference
        id: base-ref
        run: |
          if [[ "${{ github.head_ref }}" == release-please--* ]]; then
            # For release-please branches, compare against last release tag
            LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "${{ github.event.pull_request.base.ref }}")
            echo "ref=${LAST_TAG}" >> $GITHUB_OUTPUT
            echo "Comparing against last release: ${LAST_TAG}"
          else
            # For regular PRs, use base branch
            echo "ref

…

## Source & license

This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [flowcore-io](https://github.com/flowcore-io)
- **Source:** [flowcore-io/usable-pr-validator](https://github.com/flowcore-io/usable-pr-validator)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** yes
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/mcp-flowcore-io-usable-pr-validator
- Seller: https://agentstack.voostack.com/s/flowcore-io
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
