Every document filename now mirrors its lifecycle state with a status suffix (e.g., .draft.md, .wip.md, .accepted.md). No more bare .md for tracked document types. Also renamed all from_str methods to parse to avoid FromStr trait confusion, introduced StagingDeploymentParams struct, and fixed all 19 clippy warnings across the codebase. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
4.8 KiB
RFC 0013: Git Forge Integration
| Status | Implemented |
| Date | 2026-01-25 |
| Source Spike | Git Forge Integration for Blue MCP |
Problem
Blue's PR tools (blue_pr_create, blue_pr_verify, blue_pr_merge) shell out to gh CLI, which only works with GitHub. Users with Forgejo/Gitea remotes can't create PRs via Blue MCP - the commands fail silently or with cryptic errors.
This blocks the workflow for anyone not using GitHub.
Goals
- Native REST API integration for GitHub and Forgejo/Gitea
- Auto-detect forge type from git remotes
- Unified interface - same Blue tools work regardless of forge
- No external CLI dependencies (
gh,tea, etc.)
Non-Goals
- GitLab support (different API, future RFC)
- Issue management (PRs only for now)
- Full forge feature parity (minimal surface for Blue's workflow)
Proposal
1. Forge Trait
pub trait Forge: Send + Sync {
fn create_pr(&self, opts: CreatePrOpts) -> Result<PullRequest, ForgeError>;
fn get_pr(&self, owner: &str, repo: &str, number: u64) -> Result<PullRequest, ForgeError>;
fn merge_pr(&self, owner: &str, repo: &str, number: u64, strategy: MergeStrategy) -> Result<(), ForgeError>;
fn pr_is_merged(&self, owner: &str, repo: &str, number: u64) -> Result<bool, ForgeError>;
}
pub struct CreatePrOpts {
pub owner: String,
pub repo: String,
pub head: String, // branch with changes
pub base: String, // target branch
pub title: String,
pub body: Option<String>,
pub draft: bool,
}
pub enum MergeStrategy {
Merge,
Squash,
Rebase,
}
2. Implementations
GitHubForge
- Endpoint:
https://api.github.com/repos/{owner}/{repo}/pulls - Auth:
Authorization: Bearer {GITHUB_TOKEN}
ForgejoForge (works with Gitea too)
- Endpoint:
https://{host}/api/v1/repos/{owner}/{repo}/pulls - Auth:
Authorization: token {FORGEJO_TOKEN}
3. Auto-Detection
Parse git remotes to detect forge type:
fn detect_forge(remote_url: &str) -> ForgeType {
let url = parse_git_url(remote_url);
match url.host {
"github.com" => ForgeType::GitHub,
"codeberg.org" => ForgeType::Forgejo,
host if host.contains("gitea") => ForgeType::Forgejo,
host if host.contains("forgejo") => ForgeType::Forgejo,
_ => {
// Probe /api/v1/version - Forgejo/Gitea respond, GitHub doesn't
if probe_forgejo_api(&url.host) {
ForgeType::Forgejo
} else {
ForgeType::GitHub // fallback
}
}
}
}
Cache detected type in .blue/config.yaml:
forge:
type: forgejo
host: git.beyondtheuniverse.superviber.com
owner: superviber
repo: blue
4. Token Resolution
Environment variables with fallback chain:
| Forge | Variables (in order) |
|---|---|
| GitHub | GITHUB_TOKEN, GH_TOKEN |
| Forgejo | FORGEJO_TOKEN, GITEA_TOKEN |
5. Updated MCP Tools
blue_pr_create changes:
- Remove
ghCLI dependency - Use detected forge's REST API
- Return PR URL directly
Response includes forge info:
{
"status": "success",
"pr_url": "https://git.example.com/owner/repo/pulls/42",
"pr_number": 42,
"forge": "forgejo"
}
6. New Module Structure
crates/blue-core/src/
├── forge/
│ ├── mod.rs # Forge trait, ForgeType, detection
│ ├── github.rs # GitHub implementation
│ ├── forgejo.rs # Forgejo/Gitea implementation
│ └── git_url.rs # URL parsing utilities
Alternatives Considered
A. Keep shelling out to CLIs
Rejected: Requires users to install and configure gh/tea. Fragile, hard to get structured output.
B. Use existing MCP servers (forgejo-mcp, github-mcp)
Rejected: Adds external dependencies. forgejo-mcp doesn't support PR creation. Better to own the integration.
C. GitLab support in this RFC
Deferred: Different API patterns. Keep scope focused. Future RFC.
Implementation Plan
- Add
forgemodule to blue-core with trait and types - Implement
ForgejoForgewith REST client - Implement
GitHubForgewith REST client - Add auto-detection logic with caching
- Update
handle_pr_createto use forge - Update
handle_pr_verifyandhandle_pr_merge - Remove
ghCLI dependency
Test Plan
- ForgejoForge creates PR via REST API
- GitHubForge creates PR via REST API
- Auto-detection identifies github.com as GitHub
- Auto-detection identifies codeberg.org as Forgejo
- Auto-detection probes unknown hosts
- Token resolution finds FORGEJO_TOKEN
- Token resolution finds GITHUB_TOKEN
- blue_pr_create works with Forgejo remote
- blue_pr_create works with GitHub remote
- PR merge works with both forges
"One interface, many forges. The abstraction serves the worker."
— Blue