https://github.com/michidk/orcastrate
🐬 Stop copy-pasting workflow files across repos. Define canonical templates once, sync them everywhere, and get PRs when repos drift.
https://github.com/michidk/orcastrate
continuous-integration github-actions github-administration github-config rust templates
Last synced: 6 days ago
JSON representation
🐬 Stop copy-pasting workflow files across repos. Define canonical templates once, sync them everywhere, and get PRs when repos drift.
- Host: GitHub
- URL: https://github.com/michidk/orcastrate
- Owner: michidk
- License: mit
- Created: 2026-04-05T16:39:35.000Z (3 months ago)
- Default Branch: main
- Last Pushed: 2026-06-15T13:48:59.000Z (7 days ago)
- Last Synced: 2026-06-15T15:25:24.933Z (7 days ago)
- Topics: continuous-integration, github-actions, github-administration, github-config, rust, templates
- Language: Rust
- Homepage: https://github.com/michidk/orcastrate
- Size: 1.72 MB
- Stars: 5
- Watchers: 0
- Forks: 0
- Open Issues: 5
-
Metadata Files:
- Readme: README.md
- License: LICENSE
- Agents: AGENTS.md
Awesome Lists containing this project
README
> [!NOTE]
> Stop copy-pasting workflow files across repos. Define canonical templates once, sync them everywhere, and get PRs when repos drift.
## How it works
```
orchestrator repo
├── orchestrator.toml # which repos to manage
├── templates/
│ ├── rust-ci.yml # Tera-powered workflow templates
│ ├── node-ci.yml
│ └── pr-title.yml
└── .github/workflows/
└── sync.yml # scheduled Action that runs orcastrate
```
Orcastrate runs as a scheduled GitHub Action in your central orchestrator repo. On each run it:
1. Reads your repo list from `orchestrator.toml`
2. Scans each repo's `.github/workflows/` for files with `@orcastrate` frontmatter
3. Renders the referenced template with the declared params
4. Compares the rendered output against the current file
5. Opens one PR per drifted workflow
## Managed workflow frontmatter
Workflow files opt in to management via a comment block at the top:
```yaml
# @orcastrate
# template: rust-ci
# params:
# toolchain: stable
# features: ["serde", "async"]
# @end-orcastrate
name: CI
on: [push]
# ... rest of workflow managed by orcastrate
```
Only files with this block are touched. Everything else is ignored.
## Quick start
### 1. Create the orchestrator repo
Create a new repo in your org (e.g. `myorg/workflow-orchestrator`).
### 2. Add config
```toml
# orchestrator.toml
[orchestrator]
templates_dir = "templates"
[[repos]]
name = "myorg/service-api"
[[repos]]
name = "myorg/service-web"
```
### 3. Add a template
```yaml
# templates/rust-ci.yml
name: CI
on:
push:
branches: [{{ default_branch | default(value="main") }}]
pull_request:
branches: [{{ default_branch | default(value="main") }}]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@{{ toolchain | default(value="stable") }}
- run: cargo test --all-features
```
### 4. Set up the scheduled Action
```yaml
# .github/workflows/sync.yml
name: Orcastrate Sync
on:
schedule:
- cron: "0 8 * * 1-5"
workflow_dispatch:
permissions:
contents: write
pull-requests: write
jobs:
sync:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: michidk/orcastrate@v0
with:
orcastrate-token: ${{ secrets.ORCASTRATE_TOKEN }}
github-token: ${{ secrets.GITHUB_TOKEN }}
```
### 5. Add frontmatter to target repos
In each managed repo, add the frontmatter block to workflow files:
```yaml
# @orcastrate
# template: rust-ci
# params:
# toolchain: stable
# @end-orcastrate
name: CI
# ... orcastrate will manage the rest
```
## CLI usage
```
orcastrate sync # sync all repos, open PRs for drift
orcastrate sync --dry-run # see what would change without modifying anything
orcastrate sync --repo org/repo # sync a single repo
orcastrate validate # check config + templates are valid
orcastrate drift # check drift status without creating PRs
orcastrate list-repos # show configured + discovered repos
orcastrate list-templates # show available templates
```
Verbosity: `-v` for debug, `-vv` for trace, `-q` for quiet.
## Configuration
### `orchestrator.toml`
```toml
[orchestrator]
templates_dir = "templates" # where templates live
branch_prefix = "orcastrate/sync" # PR branch prefix
pr_label = "orcastrate" # label added to PRs
dry_run = false # global dry-run toggle
[[repos]]
name = "myorg/repo-a"
[[repos]]
name = "myorg/repo-b"
enabled = false # temporarily skip
# auto-discover repos by org topic
[discovery]
org = "myorg"
topic = "managed-workflows"
```
### Template params
Templates use [Tera](https://keats.github.io/tera/) (Jinja2-style) syntax. Params declared in frontmatter are injected at render time:
```yaml
# @orcastrate
# template: rust-ci
# params:
# toolchain: nightly
# features: ["serde", "tokio"]
# default_branch: develop
# @end-orcastrate
```
Templates can use defaults: `{{ toolchain | default(value="stable") }}`
## Authentication
Orcastrate uses two tokens for different operations:
| Operation | Token | Why |
|---|---|---|
| Git writes (tree, commit, ref) | `ORCASTRATE_TOKEN` | Needs `workflows` scope for `.github/workflows/` files |
| PR creation, labels | `GITHUB_TOKEN` | PRs appear as `github-actions[bot]` |
### Setup
1. Create a **fine-grained PAT** with permissions: Contents (R/W), Pull requests (R/W), Workflows (R/W)
2. Add it as a repo secret named `ORCASTRATE_TOKEN`
3. `GITHUB_TOKEN` is provided automatically by GitHub Actions
### GitHub App (recommended for orgs)
For org-wide use, create a GitHub App instead of a PAT:
- **Repository contents**: Read & Write
- **Pull requests**: Read & Write
- **Workflows**: Read & Write
Install it on your org, then set:
- `ORCASTRATE_APP_ID`
- `ORCASTRATE_PRIVATE_KEY`
- `ORCASTRATE_INSTALLATION_ID`
## What gets PRed
When orcastrate detects drift, it opens **one PR per workflow file**:
- Branch: `orcastrate/sync/{workflow-name}` (e.g. `orcastrate/sync/pr-title`)
- Title: ``chore(ci): sync `pr-title` from template `pr-title` ``
- Unified diff in the PR body
- The `orcastrate` label for easy filtering
If a PR already exists for the same workflow, it updates the existing PR instead of creating a new one.
### Example PR
See [#6](https://github.com/michidk/orcastrate/pull/6) for a real example.
[](https://github.com/michidk/orcastrate/pull/6)
## License
MIT