Skip to content

Configurable merge strategy: direct push vs pull request #473

@jrf0110

Description

@jrf0110

Overview

Local Gastown's Refinery pushes merged code directly to main — no pull request, no human review step. The Refinery IS the review: it runs quality gates (tests, lint, build) and if they pass, the code lands immediately.

This works when the human owns the repo and trusts their agents. But in the cloud — especially for org-owned towns with shared codebases and branch protection rules — teams will often want the Refinery to create a PR so humans can review agent work before it lands.

Support both as a configurable merge strategy at the town and rig level.

Parent: #204

Merge Strategies

Strategy Behavior Use case
direct Refinery squash-merges into main and pushes directly. No PR. Quality gates are the only review. Solo developers, personal repos, high-trust teams, fast iteration
pr Refinery creates a GitHub/GitLab PR from the polecat's branch. PR includes quality gate results in the description. Waits for human approval before merging. Shared codebases, org teams, repos with branch protection, compliance requirements

Configuration

Town-level config sets the default. Rig-level config can override per repo.

// Town config
{
  merge_strategy: 'direct' | 'pr',  // default: 'direct'
  // ...
}

// Rig config (overrides town default)
{
  merge_strategy?: 'direct' | 'pr',  // if unset, inherits from town
  // ...
}

Direct Strategy (default)

Same as local Gastown's current behavior:

  1. Refinery checks out main, pulls latest
  2. Squash-merges polecat branch
  3. Runs quality gates
  4. Pushes to origin main
  5. Deletes remote polecat branch
  6. Closes MR bead and source issue bead

PR Strategy

New behavior:

  1. Refinery verifies polecat branch is pushed to origin (already happens in gt done)
  2. Runs quality gates locally (tests, lint, build)
  3. Creates a PR via GitHub/GitLab API:
    • Title: from the MR bead title (which comes from the source issue)
    • Body: quality gate results, source bead ID, convoy link, agent attribution
    • Base: default branch (main)
    • Head: polecat branch
    • Labels: configurable (e.g., gastown, automated)
    • Reviewers: configurable per rig (optional)
  4. Updates the MR bead with the PR URL
  5. MR bead status → in_review
  6. Monitors PR status via webhook or polling:
    • PR merged externally → close MR bead, close source issue, delete polecat branch
    • PR closed without merge → create rework bead or escalate
    • Review comments posted → optionally dispatch a polecat to address feedback
  7. Does NOT auto-merge — waits for human approval

PR Body Template

## Gastown Agent Work

**Source**: [bead-id](dashboard-link) — {bead title}
**Agent**: {polecat name} ({model})
**Convoy**: [convoy-id](dashboard-link)

### Quality Gates

| Gate | Status | Duration |
|------|--------|----------|
| Tests | Passed | 42s |
| Typecheck | Passed | 8s |
| Lint | Passed | 3s |
| Build | Passed | 15s |

### Changes

{git diff --stat summary}

---

*Created by Gastown Refinery. [View in dashboard](dashboard-link)*

GitHub/GitLab API Integration

The container already has git credentials from the org's GitHub App installation (or GitLab token). PR creation uses these same credentials:

  • GitHub: POST /repos/{owner}/{repo}/pulls via the GitHub REST API or gh pr create CLI
  • GitLab: POST /projects/{id}/merge_requests via the GitLab API

The PR is created by the Refinery agent (if it's an LLM agent) via a new gt_create_pr tool, or by the TownDO alarm handler (if using deterministic merge processing) via direct API call.

Webhook Integration for PR Status

When merge_strategy: 'pr', the system needs to know when PRs are merged or closed:

  • GitHub webhooks: The existing webhook-handler.ts infrastructure handles pull_request events. A new handler routes PR merge/close events to the relevant TownDO, which updates the MR bead status.
  • Polling fallback: If webhooks aren't configured, the TownDO alarm periodically checks open PR statuses via the GitHub/GitLab API.

Acceptance Criteria

  • merge_strategy config field on town config and rig config
  • Rig config inherits from town config when unset
  • direct strategy works as today (push to main)
  • pr strategy creates a GitHub PR with quality gate results and agent attribution
  • pr strategy creates a GitLab MR for GitLab-backed rigs
  • MR bead tracks the platform PR URL
  • PR merge/close events (via webhook or polling) update MR bead status
  • Dashboard shows PR link on MR beads when strategy is pr

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestkilo-auto-fixAuto-generated label by Kilokilo-triagedAuto-generated label by Kilo

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions