Castellan

A merge gate and issue triage bot for GitHub. Rules decide; a model can only veto a merge, never grant one. GitHub is the only state store: castellan keeps nothing between events. GitHub is the only supported provider today.

Repository ยท RFC agent-of-empires#5502

How it decides

Castellan re-evaluates a PR from scratch on every event and posts one brief with a verdict.

  1. Skip. Drafts, dependabot, non-default bases, skipped branches and mode: off are not evaluated.
  2. Rules. Protected or release paths, migrations, failing or missing checks, CodeRabbit changes requested and size limits escalate to a human.
  3. Model review. Only a PR that passed every rule is reviewed. The model can turn a candidate into escalate; a failed review also escalates.
  4. Act. shadow posts the brief and a castellan status. enforce also approves the head SHA and enables squash auto-merge, only for merge.

Config is read from .castellan.yml on the base commit only, so a PR cannot loosen its own gate.

Status: bootstrap only. The gate is not wired into the entrypoint yet; that lands with the Lambda adapter.

Triage

While an issue carries needs-triage, castellan fills the missing priority, area:* and type labels and the project Size, Status and Priority fields. In shadow it comments the proposal; in enforce it applies it.

.castellan.yml

Every key is optional. Unknown keys are rejected and the PR escalates.

mode: shadow          # off | shadow | enforce
limits:
  maxLines: 100
  maxFiles: 5
  maxTopLevelDirs: 2
paths:
  protected: ["src/auth/"]
  release: ["Cargo.toml"]
teams:
  maintainers: maintainers
  protected: security
trustedAuthors: ["octocat"]
llm:
  provider: bedrock     # or anthropic
prompt:
  guidance:
    - Prefer small, focused changes.

Self-host

See the README for details.