CentralRepoOps
CentralRepoOps is a MultiRepoOps deployment variant where a single private repository acts as a control plane for large-scale operations across many repositories.
Use this pattern for organization-wide rollouts, phased adoption (pilot waves first), central governance, and security-aware prioritization across tens or hundreds of repositories. Each orchestrator run delivers consistent policy gates, controlled fan-out (max), and a complete decision trail — without pushing main changes to individual target repositories.
Example: Dependabot Rollout (Orchestrator + Worker)
Section titled “Example: Dependabot Rollout (Orchestrator + Worker)”This pattern maps directly to your Dependabot rollout pair:
dependabot-rollout-orchestrator.mddecides where to roll out next.dependabot-rollout.mdexecutes how to configure each target repository.
Orchestrator (central control)
Section titled “Orchestrator (central control)”Let’s say you want to roll out a new Dependabot configuration across 100 repositories. This example shows you how to do this based on a small subset.
Navigate to your central repository and create a workflow file .github/workflows/dependabot-rollout-orchestrator.md with the following contents:
---on: schedule: - cron: '0 9 * * 1'
tools: github: github-token: ${{ secrets.GH_AW_READ_ORG_TOKEN }} toolsets: [repos]
safe-outputs: dispatch-workflow: workflows: [dependabot-rollout] max: 5---
# Dependabot Rollout Orchestrator
Categorize and orchestrate Dependabot rollout across repositories.
**Target repos**: All repos in the organization
## Task
1. **Filter** - Parse repos (from input or variable), check each for existing `.github/dependabot.yml`, keep only repos without it
2. **Categorize** - Read repo contents to assess complexity: - Simple: Single package.json, <50 dependencies, standard structure - Complex: Multiple package.json files, >100 deps, or multiple ecosystems - Conflicting: Has Renovate config or custom update scripts - Security: Open security alerts or public with dependencies
3. **Prioritize** - Order repos by rollout preference: simple → security → complex → conflicting
4. **Dispatch** - Dispatch `dependabot-rollout` worker for every prioritized repository
5. **Summarize** - Report total candidates, categorization breakdown, selected repos with rationaleCompile this workflow to generate the lock file: gh aw compile.
Create a fine-grained PAT GH_AW_READ_ORG_TOKEN (this link pre-fills the token name, description, and Contents: Read permission) with the organization as an owner,
select “All repositories” (or allowlist of specific repos), and grant Repository permission: Contents: Read-only.
Add this into your Actions repository secrets. This gives the orchestrator read access to all candidate repositories.
Worker (cross-repository execution)
Section titled “Worker (cross-repository execution)”Next, create the worker workflow .github/workflows/dependabot-rollout.md in your central repository that will operate on each target repository via checkout:
---on: workflow_dispatch: inputs: target_repo: description: 'Target repository (owner/repo format)' required: true type: string
run-name: Dependabot rollout for ${{ github.event.inputs.target_repo }}
concurrency: group: gh-aw-${{ github.workflow }}-${{ github.event.inputs.target_repo }}
engine: id: copilot concurrency: group: gh-aw-copilot-${{ github.workflow }}-${{ github.event.inputs.target_repo }}
steps: - name: Checkout target repository uses: actions/checkout@v5 with: token: ${{ secrets.ORG_REPO_CHECKOUT_TOKEN }} repository: ${{ github.event.inputs.target_repo }} persist-credentials: false
permissions: contents: read issues: read pull-requests: read
tools: github: github-token: ${{ secrets.GH_AW_READ_ORG_TOKEN }} toolsets: [repos]
safe-outputs: github-token: ${{ secretsGH_AW_CROSS_REPO_PAT }} create-pull-request: target-repo: ${{ github.event.inputs.target_repo }} title-prefix: '[dependabot] ' max: 1 create-issue: target-repo: ${{ github.event.inputs.target_repo }} title-prefix: '[dependabot-config] ' max: 1---
# Intelligent Dependabot Configuration
You are creating a **customized** Dependabot configuration based on analyzing this specific repository.
**Target Repository**: ${{ github.event.inputs.target_repo }}
## Why AI is Required
You must analyze the repository structure and create an intelligent, customized configuration - not a generic template.
## Step 1: Analyze Repository
**Check for conflicts:**
- Does `.github/dependabot.yml` already exist? → Stop, create issue explaining it exists- Does `.github/renovate.json` or `renovate.json` exist? → Create issue about migrating from Renovate- Are there custom dependency update scripts? → Create issue suggesting Dependabot alternative
**Analyze package manager complexity:**
For **npm** (if package.json exists):
- Count total dependencies (dependencies + devDependencies)- Check for monorepo: Are there multiple package.json files in subdirectories?- Simple: <20 dependencies, single package.json- Complex: >100 dependencies OR monorepo structure
For **Python** (requirements.txt, setup.py, pyproject.toml):
- Count dependencies- Check for multiple requirement files
For **Go** (go.mod):
- Note if present
For **GitHub Actions** (.github/workflows/*.yml):
- Count workflow files
**Security context:**
- Use GitHub tools to check for open security alerts- If critical alerts exist, prioritize security updates
## Step 2: Create Customized Configuration
Based on your analysis, create an appropriate config:
### Simple Repository (<20 npm deps, no monorepo)
```yamlversion: 2updates: - package-ecosystem: "npm" directory: "/" schedule: interval: "daily" # Low complexity = more frequent - package-ecosystem: "github-actions" directory: "/" schedule: interval: "weekly"```
### Complex Repository (>100 deps OR security alerts)
```yamlversion: 2updates: - package-ecosystem: "npm" directory: "/" schedule: interval: "weekly" # High complexity = less frequent groups: production: patterns: ["*"] exclude-patterns: ["@types/*", "@jest/*"] dev-dependencies: patterns: ["@types/*", "@jest/*", "eslint*"]```
### Monorepo (multiple package.json)
```yamlversion: 2updates: - package-ecosystem: "npm" directory: "/packages/frontend" schedule: interval: "weekly" - package-ecosystem: "npm" directory: "/packages/backend" schedule: interval: "weekly"```
## Step 3: Deliver Configuration
**If config is straightforward (no Renovate conflict):**
- Create `.github/dependabot.yml` with your customized config- Create pull request with: - Title: "[dependabot] Add customized Dependabot configuration" - Body explaining: dependency count, why weekly vs daily, grouping strategy, etc.
**If Renovate detected:**
- Create issue explaining migration benefits and proposed config- Include generated config in issue body
**If no package managers found:**
- Create issue: "No supported package managers detected"
## Key: Explain Your Reasoning
In the PR/issue body, explain **why** you chose this specific configuration (not a generic template).Compile this workflow to generate the lock file: gh aw compile.
Create a fine-grained PAT ORG_REPO_CHECKOUT_TOKEN (this link pre-fills the token name, description, and permissions) with the organization as an owner,
select “All repositories” (or allowlist of specific repos), and grant Repository permission: Contents: Read & write, Actions: Read & write.
This allows the worker to check out the target repository.
Also create a fine-grained PAT REPO_SAFE_OUTPUTS_TOKEN (this link pre-fills the token name, description, and permissions) with the organization as an owner,
select “All repositories” (or allowlist of specific repos), and grant Repository permission: Contents: Write, Issues: Write, Pull Requests: Write.
This allows the worker to create pull requests and issues in the target repository based on the orchestrator’s instructions.
After the setup is complete, you can run the orchestrator with workflow_dispatch (target_repos) or let the schedule trigger run automatically.
Richer Triggers with a Trigger File
Section titled “Richer Triggers with a Trigger File”Embedding a schedule: trigger directly in the orchestrator is the simplest setup, but it limits the orchestrator to time-based execution only. A trigger file — a plain, hand-authored GitHub Actions workflow — solves this by separating the trigger definition from the agent logic:
- The compiled orchestrator exposes a
workflow_calltrigger. - A stable, rarely-changing
.ymlfile defines the actual GitHub events that kick off the run. - The trigger file calls the compiled orchestrator via
workflow_call, forwarding any inputs and secrets.
This means you can update when and why the orchestrator runs — reacting to a label, a repository push, a security alert, or a manual dispatch — without touching or recompiling the agentic workflow.
Add workflow_call to the Orchestrator
Section titled “Add workflow_call to the Orchestrator”Extend the orchestrator’s on: section with workflow_call and declare any inputs you want callers to pass:
---on: schedule: weekly on monday workflow_call: inputs: reason: description: "Why this run was triggered (label name, event type, etc.)" type: string default: "scheduled"
tools: github: github-token: ${{ secrets.GH_AW_READ_ORG_TOKEN }} toolsets: [repos]
safe-outputs: dispatch-workflow: workflows: [dependabot-rollout] max: 5---
# Dependabot Rollout Orchestrator
...Compile the workflow after adding workflow_call: gh aw compile.
Create the Stable Trigger File
Section titled “Create the Stable Trigger File”Add a plain GitHub Actions workflow alongside the compiled orchestrator. This file is written by hand, committed once, and rarely needs to change:
name: Central Ops Trigger
on: # Trigger when a repository is labeled for Dependabot rollout issues: types: [labeled]
# Trigger on any push to main (e.g. config change) push: branches: [main]
# Allow manual runs with context workflow_dispatch: inputs: reason: description: "Reason for manual trigger" required: false default: "manual"
jobs: trigger: uses: ./.github/workflows/dependabot-rollout-orchestrator.lock.yml with: reason: ${{ github.event_name }} secrets: inheritCalling the Orchestrator from Another Repository
Section titled “Calling the Orchestrator from Another Repository”The trigger file can also live in a different repository — for example, inside each target repo — and call back into the orchestrator in the central control repository. This lets individual repositories decide when to request a rollout without requiring direct access to the central repo.
name: Request Dependabot Rollout
on: # Trigger when a maintainer labels the repo for rollout issues: types: [labeled] workflow_dispatch:
jobs: trigger: # Call the orchestrator workflow in the central control repo uses: my-org/central-ops/.github/workflows/dependabot-rollout-orchestrator.lock.yml@main with: reason: "${{ github.event_name }} in ${{ github.repository }}" secrets: GH_AW_READ_ORG_TOKEN: ${{ secrets.GH_AW_READ_ORG_TOKEN }}Trade-offs: Schedule Only vs Trigger File
Section titled “Trade-offs: Schedule Only vs Trigger File”| Schedule only | Trigger file + workflow_call | |
|---|---|---|
| Setup | Single file, no extra config | Two files (orchestrator + trigger file) |
| Trigger flexibility | Cron/schedule only | Any GitHub event (issues, push, PRs, labels…) |
| Change trigger without recompile | No — trigger is embedded in the agentic workflow | Yes — edit the plain .yml trigger file |
| Pass event context to agent | Not possible | Yes — via workflow_call inputs |
| Stability | Trigger changes on every recompile | Trigger file stays fixed across recompiles |
| When to use | Simple recurring jobs with no event dependency | Jobs that should react to repository activity or need flexible scheduling |
The schedule-only approach is perfectly fine for a standalone nightly or weekly orchestrator. Move to the trigger file pattern when you need to react to repository events, pass extra context to the agent, or decouple trigger changes from the compilation cycle.
Cross-Repository Trigger File
Section titled “Cross-Repository Trigger File”A trigger file can live in a different repository (for example, in each application repo) and call back into the agentic workflow hosted in a central platform repo. This pattern is useful for multi-tenant platforms where each application repo triggers a shared agentic workflow.
name: Platform Relay
on: issue_comment: types: [created]
jobs: relay: uses: my-org/platform-repo/.github/workflows/platform-gateway.lock.yml@main with: issue_number: ${{ github.event.issue.number }} source_repo: ${{ github.repository }} secrets: inheritRepository Visibility
Section titled “Repository Visibility”The callee (platform) repository must meet one of these requirements:
- Public — accessible to anyone
- Internal — accessible within the organization
- Private with Actions access — in repository Settings → Actions → General, under Access, select “Accessible from repositories in the [organization] organization”
Secrets Configuration
Section titled “Secrets Configuration”COPILOT_GITHUB_TOKEN must be configured in the caller repository’s secrets. When using secrets: inherit, all caller secrets are forwarded to the platform workflow automatically. This means:
- Premium Copilot requests bill to the caller’s token, not the platform’s
- Each application team manages their own
COPILOT_GITHUB_TOKEN - The platform repo does not need to hold tokens for all callers
How It Works
Section titled “How It Works”When the compiler detects workflow_call in the on: section, it generates a cross-repo-aware checkout step in the activation job. Instead of always checking out github.repository (which is the caller in a workflow_call context), the step uses a conditional expression:
repository: ${{ github.event_name == 'workflow_call' && github.action_repository || github.repository }}This ensures the activation job checks out the platform repo’s .github folder — where the workflow markdown and runtime imports live — regardless of which application repo triggered the workflow. For non-workflow_call events, the expression falls back to the current repository.
Best Practices
Section titled “Best Practices”- Keep orchestrator permissions narrow; delegate repo-specific writes to workers.
- Use safe output limits (
max) and explicit target workflow allowlists. - Add correlation IDs to worker dispatch inputs for tracking.
Related Patterns
Section titled “Related Patterns”- MultiRepoOps - Cross-repository automation capability
- Cross-Repository Operations - Checkout and target-repo configuration
- Orchestration - Generic orchestrator/worker dispatch pattern
- SideRepoOps - Isolated control-plane setup