Skip to main content
Like AOF? Give us a star!
If you find AOF useful, please star us on GitHub. It helps us reach more developers and grow the community.

GitHub Integration Reference

Complete reference for GitHub platform integration with AOF.

Platform Support Statusโ€‹

PlatformStatusNotes
GitHubโœ… StableFully tested, production-ready
GitLab๐Ÿงช ExperimentalImplemented but untested - contributions welcome
Bitbucket๐Ÿงช ExperimentalImplemented but untested - contributions welcome

Important:

  • This documentation focuses on GitHub, which is the only fully tested and supported Git platform at this time
  • GitLab and Bitbucket adapters exist in the codebase with similar API patterns, but have not been validated in real-world usage
  • If you're interested in using GitLab or Bitbucket, we encourage you to test and contribute improvements to these integrations

Overviewโ€‹

AOF provides deep GitHub integration through webhook-based triggers and the GitHub API, enabling agents to automate pull request reviews, issue management, CI/CD checks, and deployment workflows.

Key Capabilities:

  • Automatic PR code review with AI analysis
  • Issue triage and auto-labeling
  • CI/CD check runs and status updates
  • Deployment automation on merge events
  • Comment posting and review submission
  • Multi-repository synchronization

Architectureโ€‹

GitHub integration consists of three components:

  1. GitHub Trigger - Receives webhook events from GitHub
  2. GitHub Platform Adapter - Parses events and manages API calls
  3. Agents/Flows - Process events and take actions
GitHub Webhook โ†’ AOF Daemon โ†’ Trigger โ†’ Agent/Flow โ†’ GitHub API

Configuration Referenceโ€‹

Daemon Configurationโ€‹

The DaemonConfig enables GitHub as a platform and points to resource directories. Command routing and filtering are defined in Triggers, not here.

Configure GitHub platform in daemon.yaml:

apiVersion: aof.dev/v1
kind: DaemonConfig
metadata:
name: aof-daemon

spec:
server:
port: 3000
host: "0.0.0.0"
cors: true
timeout_secs: 60

# Enable platforms - just enables the webhook endpoint
# Command routing is defined in Triggers
platforms:
github:
enabled: true
token_env: GITHUB_TOKEN # Environment variable name
webhook_secret_env: GITHUB_WEBHOOK_SECRET
bot_name: aofbot # Optional: for @mentions

# Resource discovery
triggers:
directory: ./triggers/
watch: true

agents:
directory: ./agents/

fleets:
directory: ./fleets/

flows:
directory: ./flows/
enabled: true

runtime:
max_concurrent_tasks: 10
task_timeout_secs: 300

Platform Configuration Fieldsโ€‹

FieldTypeRequiredDescription
enabledboolYesEnable GitHub webhook endpoint (/webhook/github)
token_envstringYesEnvironment variable name for GitHub token
webhook_secret_envstringYesEnvironment variable name for webhook secret
bot_namestringNoBot name for @mentions (default: "aofbot")

Note: Event filtering, repository filtering, and command routing are configured in Trigger files, not in DaemonConfig. This separation keeps the daemon config minimal and allows per-trigger customization.

Trigger Configurationโ€‹

Create trigger in triggers/github-pr.yaml:

apiVersion: aof.dev/v1
kind: Trigger
metadata:
name: github-pr-events

spec:
type: GitHub

config:
webhook_secret: ${GITHUB_WEBHOOK_SECRET}

# Event filters
github_events:
- pull_request
- pull_request_review
- pull_request_review_comment

# Repository filters
repositories:
- "myorg/api"
- "myorg/web"

# Branch filters (for push events)
branches:
- "main"
- "develop"
- "release/*"

# Route to agent or flow
commands:
/review:
agent: code-reviewer
description: "Review pull request"

/deploy:
flow: deploy-flow
description: "Deploy to production"

default_agent: github-assistant

Multi-Repository Configurationโ€‹

AOF uses a single DaemonConfig + multiple Triggers architecture. This allows you to:

  • Use one webhook URL for all repositories
  • Configure different commands per repository or repository group
  • Assign different teams/agents to different repos

Architecture Overviewโ€‹

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ GitHub Webhook (single URL: /webhook/github) โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
โ”‚
โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ DaemonConfig (global) โ”‚
โ”‚ - Enables GitHub platform โ”‚
โ”‚ - Points to triggers/ directory โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
โ”‚
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ–ผ โ–ผ โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ frontend.yaml โ”‚ โ”‚ backend.yaml โ”‚ โ”‚ infra.yaml โ”‚
โ”‚ repos: web-*, ui โ”‚ โ”‚ repos: api-*, svcโ”‚ โ”‚ repos: terraform โ”‚
โ”‚ fleet: frontend โ”‚ โ”‚ fleet: backend โ”‚ โ”‚ fleet: platform โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Example: Per-Team Triggersโ€‹

Directory structure:

config/
daemon.yaml # Global config

triggers/
github-frontend.yaml # Frontend team repos
github-backend.yaml # Backend team repos
github-infra.yaml # Platform team repos
github-docs.yaml # Documentation repos

Frontend trigger (triggers/github-frontend.yaml):

apiVersion: aof.dev/v1
kind: Trigger
metadata:
name: frontend-pr-bot
labels:
team: frontend

spec:
type: GitHub
config:
webhook_secret: ${GITHUB_WEBHOOK_SECRET}

# Only handle frontend repositories
repositories:
- "myorg/web-app"
- "myorg/mobile-app"
- "myorg/ui-components"

github_events:
- pull_request
- issue_comment

commands:
pull_request.opened:
fleet: frontend-review-fleet

/review:
fleet: frontend-review-fleet

/test:
agent: jest-runner

/storybook:
agent: storybook-deployer

default_agent: frontend-helper

Backend trigger (triggers/github-backend.yaml):

apiVersion: aof.dev/v1
kind: Trigger
metadata:
name: backend-pr-bot
labels:
team: backend

spec:
type: GitHub
config:
webhook_secret: ${GITHUB_WEBHOOK_SECRET}

repositories:
- "myorg/api-server"
- "myorg/data-pipeline"
- "myorg/auth-service"

# Restrict to backend team members
allowed_users:
- "alice"
- "bob"
- "charlie"

commands:
pull_request.opened:
fleet: backend-review-fleet

/review:
fleet: backend-review-fleet

/deploy staging:
flow: deploy-backend-staging

/deploy production:
flow: deploy-backend-prod
params:
require_approval: true

default_agent: backend-helper

Infrastructure trigger (triggers/github-infra.yaml):

apiVersion: aof.dev/v1
kind: Trigger
metadata:
name: infra-pr-bot
labels:
team: platform

spec:
type: GitHub
config:
webhook_secret: ${GITHUB_WEBHOOK_SECRET}

repositories:
- "myorg/terraform-*" # Wildcard pattern
- "myorg/k8s-manifests"
- "myorg/helm-charts"

commands:
pull_request.opened:
fleet: infra-review-fleet

/plan:
agent: terraform-planner

/apply:
flow: terraform-apply-flow
params:
require_approval: true
approvers: ["platform-lead", "sre-oncall"]

default_agent: infra-helper

Webhook Routingโ€‹

When a webhook arrives, AOF:

  1. Parses the repository from the event payload
  2. Matches against repositories patterns in each Trigger
  3. Routes to the first matching Trigger
  4. If no match, event is ignored (logged as unhandled)

Pattern matching:

  • "myorg/repo" - Exact match
  • "myorg/*" - All repos in org
  • "myorg/prefix-*" - Repos starting with prefix

Multi-Organization Supportโ€‹

Current Status: AOF currently supports multiple organizations through multiple Triggers, but requires the same webhook secret for all.

Future Enhancement: Native multi-org support with per-org secrets and GitHub App installation is tracked in GitHub Issue #46.

Current approach - Multiple triggers, same webhook secret:

# triggers/org1-repos.yaml
spec:
type: GitHub
config:
webhook_secret: ${GITHUB_WEBHOOK_SECRET}
repositories:
- "org1/*"

# triggers/org2-repos.yaml
spec:
type: GitHub
config:
webhook_secret: ${GITHUB_WEBHOOK_SECRET} # Same secret
repositories:
- "org2/*"

Limitation: All orgs must use the same webhook secret. This works but isn't ideal for enterprise multi-tenant scenarios.

Future design (Issue #46):

# Future: Per-org configuration
platforms:
github:
organizations:
- name: org1
token_env: ORG1_GITHUB_TOKEN
webhook_secret_env: ORG1_WEBHOOK_SECRET
- name: org2
token_env: ORG2_GITHUB_TOKEN
webhook_secret_env: ORG2_WEBHOOK_SECRET

Environment Variablesโ€‹

# Required
export GITHUB_TOKEN="ghp_xxxxx" # Personal Access Token
export GITHUB_WEBHOOK_SECRET="random-secret" # Webhook HMAC secret

# Optional - for GitHub App
export GITHUB_APP_ID="123456"
export GITHUB_APP_PRIVATE_KEY_PATH="/path/to/key.pem"
export GITHUB_INSTALLATION_ID="12345678"

# LLM provider
export GOOGLE_API_KEY="xxxxx"
# OR
export ANTHROPIC_API_KEY="xxxxx"

Event Referenceโ€‹

Supported Eventsโ€‹

AOF supports all major GitHub webhook events:

Event TypeDescriptionCommon Actions
pull_requestPR lifecycle eventsopened, synchronize, closed, reopened
pull_request_reviewPR review submittedsubmitted, edited, dismissed
pull_request_review_commentComment on PR diffcreated, edited, deleted
pushCode pushed to branchN/A (no action field)
issuesIssue lifecycleopened, edited, closed, reopened, labeled
issue_commentComment on issue/PRcreated, edited, deleted
workflow_runGitHub Actions workflowcompleted, requested, in_progress
check_runCheck run updatedcreated, completed, rerequested
check_suiteCheck suite updatedcompleted, requested
releaseRelease publishedpublished, created, edited
createBranch/tag createdN/A
deleteBranch/tag deletedN/A
forkRepository forkedN/A
starRepository starredcreated, deleted
watchRepository watchedstarted

Event Actionsโ€‹

pull_request Actionsโ€‹

ActionDescription
openedNew PR created
synchronizePR updated with new commits
reopenedClosed PR reopened
closedPR closed (check merged field)
editedPR title/body edited
labeled / unlabeledLabels changed
assigned / unassignedAssignees changed
review_requestedReviewers requested
ready_for_reviewDraft converted to ready
converted_to_draftReady converted to draft

issues Actionsโ€‹

ActionDescription
openedNew issue created
editedIssue title/body edited
closed / reopenedState changed
labeled / unlabeledLabels changed
assigned / unassignedAssignees changed
milestoned / demilestonedMilestone changed
pinned / unpinnedPinned status changed
locked / unlockedConversation locked/unlocked

issue_comment / pull_request_review_comment Actionsโ€‹

ActionDescription
createdNew comment posted
editedComment edited
deletedComment deleted

workflow_run Actionsโ€‹

ActionDescription
requestedWorkflow queued
in_progressWorkflow running
completedWorkflow finished (check conclusion field)

Workflow Conclusions:

  • success - All jobs passed
  • failure - One or more jobs failed
  • cancelled - Workflow cancelled
  • neutral - Neutral result
  • skipped - Workflow skipped
  • timed_out - Workflow timed out

Context Variablesโ€‹

When an agent is triggered by a GitHub event, these variables are available in metadata:

Common Variablesโ€‹

VariableTypeDescription
event_typestringEvent type (pull_request, push, etc.)
actionstringEvent action (opened, closed, etc.)
repo_idintegerRepository ID
repo_full_namestringRepository (owner/repo)
repo_privatebooleanIs repository private
sender_idintegerUser ID who triggered event
sender_loginstringUsername who triggered event

Pull Request Variablesโ€‹

Available when event_type = pull_request:

VariableTypeDescription
pr_numberintegerPR number
pr_titlestringPR title
pr_statestringopen, closed
pr_draftbooleanIs draft PR
pr_base_refstringBase branch name
pr_head_refstringHead branch name
pr_head_shastringHead commit SHA
pr_additionsintegerLines added
pr_deletionsintegerLines deleted
pr_changed_filesintegerFiles changed
pr_html_urlstringPR web URL

Issue Variablesโ€‹

Available when event_type = issues:

VariableTypeDescription
issue_numberintegerIssue number
issue_titlestringIssue title
issue_statestringopen, closed
issue_html_urlstringIssue web URL

Push Variablesโ€‹

Available when event_type = push:

VariableTypeDescription
refstringGit ref (refs/heads/main)
before_shastringPrevious commit SHA
after_shastringNew commit SHA
commit_countintegerNumber of commits pushed

Usage in Agent Instructionsโ€‹

spec:
instructions: |
You are reviewing PR #{{ metadata.pr_number }}.

Repository: {{ metadata.repo_full_name }}
Base branch: {{ metadata.pr_base_ref }}
Head branch: {{ metadata.pr_head_ref }}
Commit: {{ metadata.pr_head_sha }}

Changes: +{{ metadata.pr_additions }} -{{ metadata.pr_deletions }}
Files changed: {{ metadata.pr_changed_files }}

API Actionsโ€‹

Actions agents can perform on GitHub via built-in tools.

Post Commentโ€‹

Post a comment on an issue or PR.

# In agent instructions
tools:
- github_post_comment

# Usage
Post a comment to PR #{{ metadata.pr_number }}:
"โœ… Code review passed. Looks good!"

Rust API:

platform.post_comment("owner", "repo", 42, "โœ… Review complete").await?;

Parameters:

  • owner (string) - Repository owner
  • repo (string) - Repository name
  • issue_number (integer) - Issue or PR number
  • body (string) - Comment text (supports Markdown)

Returns: Comment ID

Post Reviewโ€‹

Submit a PR review with approval/changes/comments.

# Usage in agent
Submit a PR review with status "APPROVE" and body "LGTM! โœ…"

Rust API:

platform.post_review("owner", "repo", 42, "LGTM! โœ…", "APPROVE").await?;

Parameters:

  • owner (string) - Repository owner
  • repo (string) - Repository name
  • pr_number (integer) - Pull request number
  • body (string) - Review body (supports Markdown)
  • event (string) - Review type

Review Types:

EventDescription
APPROVEApprove the PR
REQUEST_CHANGESRequest changes before merge
COMMENTComment without explicit approval

Returns: Review ID

Create Check Runโ€‹

Create or update a CI/CD check run.

# Usage
Create check run "AI Code Review" for commit {{ metadata.pr_head_sha }}
Status: "in_progress"

Rust API:

use CheckRunOutput;

let output = CheckRunOutput {
title: "Review Complete".to_string(),
summary: "All checks passed".to_string(),
text: Some("Detailed findings...".to_string()),
};

platform.create_check_run(
"owner",
"repo",
"abc123", // head_sha
"AI Code Review",
"completed",
Some("success"),
Some(output)
).await?;

Parameters:

  • owner (string) - Repository owner
  • repo (string) - Repository name
  • head_sha (string) - Commit SHA
  • name (string) - Check run name
  • status (string) - queued, in_progress, completed
  • conclusion (string, optional) - Required if status=completed
  • output (object, optional) - Detailed output

Status Values:

  • queued - Check is queued
  • in_progress - Check is running
  • completed - Check finished

Conclusion Values (when status=completed):

  • success - Check passed
  • failure - Check failed
  • neutral - Neutral result
  • cancelled - Check cancelled
  • skipped - Check skipped
  • timed_out - Check timed out
  • action_required - Action required

Returns: Check run ID

Add Labelsโ€‹

Add one or more labels to an issue or PR.

platform.add_labels("owner", "repo", 42, &["bug", "priority:high"]).await?;

Parameters:

  • owner (string) - Repository owner
  • repo (string) - Repository name
  • issue_number (integer) - Issue or PR number
  • labels (array of strings) - Label names

Remove Labelโ€‹

Remove a label from an issue or PR.

platform.remove_label("owner", "repo", 42, "wip").await?;

Parameters:

  • owner (string) - Repository owner
  • repo (string) - Repository name
  • issue_number (integer) - Issue or PR number
  • label (string) - Label name

Securityโ€‹

Webhook Verificationโ€‹

AOF automatically validates webhook signatures using HMAC-SHA256.

How it works:

  1. GitHub sends signature in X-Hub-Signature-256 header
  2. AOF computes HMAC using webhook_secret
  3. Signatures must match or request is rejected

Configuration:

spec:
config:
webhook_secret: ${GITHUB_WEBHOOK_SECRET} # Required

Generate secure secret:

openssl rand -hex 32

Token Permissionsโ€‹

Required permissions for Personal Access Token:

PermissionAccessUse Case
ContentsRead & WriteRead code, create commits
Pull requestsRead & WriteReview PRs, post reviews
IssuesRead & WriteManage issues, post comments
ChecksRead & WriteCreate check runs
WorkflowsRead & WriteTrigger workflows
MetadataReadAccess repository metadata

For GitHub App:

Create app with same permissions, generate private key, and install on repositories.

Repository Filteringโ€‹

Whitelist repositories for security:

allowed_repos:
- "myorg/repo1" # Specific repo
- "myorg/*" # All repos in org
- "owner/private-repo" # Private repos

User Filteringโ€‹

Restrict who can trigger actions by GitHub username (login):

# In Trigger config section
config:
allowed_users:
- "alice" # GitHub username
- "bob" # GitHub username
- "ci-bot" # Bot accounts work too
- "dependabot[bot]" # GitHub Apps use [bot] suffix

Events from users not in this list will be ignored.

Current limitation: User filtering is based on GitHub usernames only. Team-based or role-based authorization (e.g., "all members of @myorg/sre-team") is not yet implemented but is planned for a future release.


Rate Limitingโ€‹

GitHub API Limitsโ€‹

TypeLimitReset
Authenticated (PAT)5,000 requests/hourHourly
GitHub App15,000 requests/hourHourly
Search API30 requests/minutePer minute

Mitigation Strategiesโ€‹

  1. Use conditional requests - Cache responses with ETags
  2. Batch operations - Combine multiple changes
  3. Use GraphQL - Fetch exactly what you need
  4. Implement backoff - Retry with exponential backoff
  5. Use GitHub App - Higher rate limits than PAT

Check rate limit:

curl -H "Authorization: Bearer $GITHUB_TOKEN" \
https://api.github.com/rate_limit

AOF handles retries automatically when rate limit is hit.


Examplesโ€‹

Quick Referenceโ€‹

Auto-Review PRโ€‹

apiVersion: aof.dev/v1
kind: Trigger
metadata:
name: pr-review

spec:
type: GitHub
config:
webhook_secret: ${GITHUB_WEBHOOK_SECRET}
github_events:
- pull_request

default_agent: code-reviewer
# agents/code-reviewer.yaml
apiVersion: aof.dev/v1
kind: Agent
metadata:
name: code-reviewer

spec:
model: google:gemini-2.5-flash

instructions: |
Review PR #{{ metadata.pr_number }} in {{ metadata.repo_full_name }}.

1. Analyze the diff for security issues
2. Check code quality and style
3. Verify test coverage
4. Post inline comments on issues
5. Submit review with APPROVE or REQUEST_CHANGES

tools:
- github_post_comment
- github_post_review

Auto-Label Issuesโ€‹

apiVersion: aof.dev/v1
kind: Trigger
metadata:
name: issue-triage

spec:
type: GitHub
config:
github_events:
- issues

default_agent: issue-triager
# agents/issue-triager.yaml
apiVersion: aof.dev/v1
kind: Agent
metadata:
name: issue-triager

spec:
model: google:gemini-2.5-flash

instructions: |
Analyze issue #{{ metadata.issue_number }} and:

1. Add appropriate labels: bug, enhancement, documentation, etc.
2. Classify priority: low, medium, high, critical
3. Identify component: api, frontend, database, etc.
4. Post a helpful comment if info is missing

tools:
- github_add_labels
- github_post_comment

Deploy on Mergeโ€‹

apiVersion: aof.dev/v1
kind: Trigger
metadata:
name: production-deploy

spec:
type: GitHub
config:
github_events:
- pull_request
branches:
- main

commands:
/deploy:
flow: deploy-flow

Create Check Runโ€‹

spec:
instructions: |
Create check run for commit {{ metadata.pr_head_sha }}:

Name: "AI Security Scan"
Status: "in_progress"

# Run security analysis...

Update check run to "completed" with conclusion "success"
Output:
Title: "Security Scan Passed"
Summary: "No vulnerabilities found"

Webhook Setupโ€‹

1. Create Webhook in GitHubโ€‹

Repository Settings:

  1. Go to Settings โ†’ Webhooks โ†’ Add webhook
  2. Configure:
    • Payload URL: https://your-domain.com/webhook/github
    • Content type: application/json
    • Secret: Your GITHUB_WEBHOOK_SECRET value
    • SSL verification: Enable
    • Events: Select events or "Send me everything"

Organization Settings:

  1. Go to Organization Settings โ†’ Webhooks
  2. Same configuration as above
  3. Applies to all repos in organization

2. Expose Endpointโ€‹

For production: Deploy with public HTTPS endpoint:

# HTTPS required
https://your-domain.com/webhook/github

For local testing: Use a tunnel service:

# Option 1: Cloudflared (no signup)
brew install cloudflared
cloudflared tunnel --url http://localhost:3000

# Option 2: ngrok (free account)
ngrok http 3000

Use tunnel URL as webhook payload URL.

3. Verify Webhookโ€‹

  1. Send test event in GitHub webhook settings
  2. Check "Recent Deliveries" for response
  3. Verify AOF logs show received event
# Check logs
tail -f /var/log/aof/daemon.log

# Look for:
# INFO GitHub webhook received: pull_request
# INFO Posted comment 123456 to owner/repo#42

Troubleshootingโ€‹

Webhook Not Triggeringโ€‹

Symptoms: GitHub webhook shows success but agent doesn't run

Solutions:

  1. Check webhook delivery logs in GitHub
  2. Verify webhook secret matches GITHUB_WEBHOOK_SECRET
  3. Check firewall allows GitHub IPs: 140.82.112.0/20, 185.199.108.0/22
  4. Verify daemon is running: aofctl serve --config daemon.yaml
  5. Check logs: RUST_LOG=debug aofctl serve

Signature Verification Failedโ€‹

Symptoms: Invalid GitHub signature in logs

Solutions:

  1. Verify GITHUB_WEBHOOK_SECRET matches webhook configuration
  2. Check webhook content type is application/json
  3. Ensure no proxy modifying request body

Cannot Post Commentsโ€‹

Symptoms: Agent runs but comments don't appear

Solutions:

  1. Verify GITHUB_TOKEN has correct permissions
  2. Check token has pull_requests:write and issues:write
  3. Test token manually:
    curl -H "Authorization: Bearer $GITHUB_TOKEN" \
    https://api.github.com/user
  4. Verify enable_comments: true in daemon config

Rate Limit Exceededโ€‹

Symptoms: API rate limit exceeded error

Solutions:

  1. Check rate limit status:
    curl -H "Authorization: Bearer $GITHUB_TOKEN" \
    https://api.github.com/rate_limit
  2. Reduce event frequency (use action filters)
  3. Use GitHub App for higher limits (15,000/hour)
  4. Implement request caching

Check Run Not Updatingโ€‹

Symptoms: Check run shows "queued" forever

Solutions:

  1. Verify token has checks:write permission
  2. Check head_sha matches actual commit
  3. Verify conclusion is valid: success, failure, neutral, etc.
  4. Use correct check run ID for updates

Best Practicesโ€‹

1. Filter Events Wiselyโ€‹

โŒ Too broad:

github_events:
- pull_request # All PR actions
- issues # All issue actions
- push # All pushes

โœ… Specific:

github_events:
- pull_request
actions:
- opened
- synchronize
branches:
- main
- develop

2. Use Repository Filtersโ€‹

For production:

allowed_repos:
- "myorg/production-api"
- "myorg/production-web"

Prevents accidental automation on test repos.

3. Implement Approval Gatesโ€‹

For destructive actions:

spec:
instructions: |
Before deploying to production:

1. Check PR has required approvals (2+)
2. Verify all checks passed
3. Ensure no "do-not-merge" labels
4. Check deployment window (weekdays 9-5)
5. Post deployment plan for human approval

4. Use Check Runs for CI/CDโ€‹

Instead of posting comments, use check runs:

  • Show up in PR checks section
  • Block merge if failed
  • Provide structured output
  • Better UX than comment spam

5. Cache GitHub Dataโ€‹

Reduce API calls by caching:

spec:
memory: "File:./github-cache.json:1000"

Enterprise Scalingโ€‹

Current Architectureโ€‹

The AOF daemon is a single-process server that:

  • Receives webhooks on a single HTTP endpoint
  • Loads all Triggers from the configured directory
  • Routes events to matching Triggers
  • Executes agents/fleets/flows for each event

Current capacity (single instance):

  • Handles ~100-500 webhook events/minute (depending on agent complexity)
  • Loads 100s of Trigger files efficiently
  • Suitable for small-to-medium teams (up to ~50 repositories)

Scaling Challengesโ€‹

For enterprise scale (1000s of repos, multiple orgs, high throughput), current limitations include:

ChallengeCurrent StateImpact
Single processOne daemon handles all eventsSingle point of failure
In-memory triggersTriggers loaded at startupMemory grows with trigger count
No queueSynchronous webhook processingBackpressure under load
Shared credentialsOne token for all reposNo org isolation

Enterprise Deployment (Kubernetes)โ€‹

Future Enhancement: Native horizontal scaling with Redis/NATS message queue is tracked in GitHub Issue #47.

Recommended architecture for enterprise:

                    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ Ingress/LB โ”‚
โ”‚ (nginx/traefik)โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
โ”‚
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ–ผ โ–ผ โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ AOF Daemon โ”‚ โ”‚ AOF Daemon โ”‚ โ”‚ AOF Daemon โ”‚
โ”‚ (replica 1) โ”‚ โ”‚ (replica 2) โ”‚ โ”‚ (replica 3) โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”˜
โ”‚ โ”‚ โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ Redis/NATS โ”‚
โ”‚ (message queue)โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
โ”‚
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ–ผ โ–ผ โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ AOF Worker โ”‚ โ”‚ AOF Worker โ”‚ โ”‚ AOF Worker โ”‚
โ”‚ (executor) โ”‚ โ”‚ (executor) โ”‚ โ”‚ (executor) โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Current workaround - Multiple daemon instances with trigger sharding:

# Kubernetes Deployment - Shard by org/team
apiVersion: apps/v1
kind: Deployment
metadata:
name: aof-daemon-frontend
spec:
replicas: 2
template:
spec:
containers:
- name: aof
image: ghcr.io/agenticdevops/aof:latest
args:
- serve
- --config=/config/daemon.yaml
volumeMounts:
- name: triggers
mountPath: /triggers
subPath: frontend # Only frontend triggers
# Separate deployment for backend team
apiVersion: apps/v1
kind: Deployment
metadata:
name: aof-daemon-backend
spec:
replicas: 2
template:
spec:
containers:
- name: aof
volumeMounts:
- name: triggers
mountPath: /triggers
subPath: backend # Only backend triggers

Ingress routing by org:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: aof-ingress
annotations:
nginx.ingress.kubernetes.io/use-regex: "true"
spec:
rules:
- host: aof.example.com
http:
paths:
# Route by X-GitHub-Delivery header or body parsing
- path: /webhook/github
pathType: Prefix
backend:
service:
name: aof-daemon-router
port:
number: 3000

Scaling Recommendationsโ€‹

ScaleReposEvents/minRecommended Setup
Small1-501-100Single daemon, single node
Medium50-200100-5002-3 daemon replicas, load balanced
Large200-1000500-2000Sharded by org/team, separate deployments
Enterprise1000+2000+Message queue + worker pools (Issue #47)

High Availabilityโ€‹

Current approach:

# Run multiple replicas behind load balancer
apiVersion: apps/v1
kind: Deployment
spec:
replicas: 3
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
maxSurge: 1

Health checks:

livenessProbe:
httpGet:
path: /health
port: 3000
initialDelaySeconds: 10
periodSeconds: 30

readinessProbe:
httpGet:
path: /ready
port: 3000
initialDelaySeconds: 5
periodSeconds: 10

Configuration Managementโ€‹

GitOps with triggers in ConfigMap:

apiVersion: v1
kind: ConfigMap
metadata:
name: aof-triggers
data:
github-frontend.yaml: |
apiVersion: aof.dev/v1
kind: Trigger
metadata:
name: frontend-pr-bot
spec:
type: GitHub
config:
repositories: ["myorg/web-*"]
commands:
/review:
fleet: frontend-review

Hot-reload triggers:

spec:
triggers:
directory: /triggers
watch: true # Watches for ConfigMap updates

Future Roadmapโ€‹

See these issues for enterprise features:


See Alsoโ€‹