https://github.com/babarot/gh-infra
Declarative GitHub infrastructure management via YAML
https://github.com/babarot/gh-infra
cli gh-extension github go
Last synced: 1 day ago
JSON representation
Declarative GitHub infrastructure management via YAML
- Host: GitHub
- URL: https://github.com/babarot/gh-infra
- Owner: babarot
- Created: 2026-03-20T15:39:20.000Z (29 days ago)
- Default Branch: main
- Last Pushed: 2026-04-11T03:41:46.000Z (7 days ago)
- Last Synced: 2026-04-11T04:23:45.341Z (7 days ago)
- Topics: cli, gh-extension, github, go
- Language: Go
- Homepage: http://babarot.github.io/gh-infra
- Size: 45.6 MB
- Stars: 86
- Watchers: 1
- Forks: 1
- Open Issues: 3
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- Codeowners: .github/CODEOWNERS
Awesome Lists containing this project
README
# gh-infra
[](https://github.com/babarot/gh-infra/actions/workflows/build.yaml)
[](https://github.com/babarot/gh-infra/actions/workflows/build.yaml)
Declarative GitHub infrastructure management via YAML. Like Terraform, but for GitHub — no state file required.
```bash
gh infra plan # Show what would change
gh infra apply # Apply the changes
```
📖 **[babarot.github.io/gh-infra](https://babarot.github.io/gh-infra/introduction/getting-started/)** — Full YAML reference, usage patterns, and guides.
## Why
The [Terraform GitHub Provider](https://registry.terraform.io/providers/integrations/github/latest/docs) covers most GitHub-as-Code use cases, but it's overkill for personal or small-team use — provider installation, HCL, state files, and state locking add real overhead before you can change a single setting.
gh-infra takes a different approach:
- **YAML instead of HCL.** Declare what your repos should look like in plain YAML.
- **No state file.** GitHub itself is the source of truth. Every `plan` fetches the live state and diffs directly — there's nothing to store, lock, or lose.
- **`plan` before `apply`.** See exactly what will change before it happens. Most alternatives (Probot Settings, GHaC) apply immediately with no preview.
- **One file, many repos.** A single `RepositorySet` can enforce consistent settings across dozens of repositories. No more clicking through the UI one repo at a time.
- **Just `gh` and a token.** No GitHub App, no server, no extra infrastructure. If you can run `gh`, you can run `gh infra`.
## Install
```bash
gh extension install babarot/gh-infra
```
### Agent Skills (optional)
Install gh-infra skills for your coding agent (Claude Code, Copilot, Codex, Cursor, etc.):
```bash
# via GitHub CLI (v2.90.0+)
gh skill install babarot/gh-infra
# via npx
npx skills add babarot/gh-infra
```
This gives your agent knowledge of gh-infra commands, YAML schema, and CI/CD patterns so it can write and manage manifests for you.
## Quick Start
### 1. Import an existing repository
```bash
gh infra import babarot/my-project > my-project.yaml
```
### 2. Edit the YAML to your desired state
```diff
apiVersion: gh-infra/v1
kind: Repository
metadata:
name: my-project
owner: babarot
spec:
description: "My awesome project"
visibility: public
topics:
- go
- cli
features:
issues: true
- projects: false
+ projects: true
wiki: false
discussions: true
```
### 3. Plan and apply
```bash
gh infra plan
gh infra apply
```
## Commands
| Command | Description |
|---------|-------------|
| `plan [path]` | Show diff between YAML and current GitHub state |
| `apply [path]` | Apply changes (with confirmation prompt) |
| `import ` | Export existing repo settings as YAML |
| `validate [path]` | Check YAML syntax and schema |
## Path Resolution
`plan`, `apply`, and `validate` accept an optional `[path]` argument:
| Argument | Example | Behavior |
|----------|---------|----------|
| *(none)* or `.` | `gh infra plan` | All `*.yaml` / `*.yml` in the current directory |
| File | `gh infra plan repos/my-cli.yaml` | That file only |
| Directory | `gh infra plan repos/` | All `*.yaml` / `*.yml` directly under it (subdirectories are ignored) |
YAML files that are not gh-infra manifests (e.g., GitHub Actions workflows, docker-compose) are silently skipped. Use `--fail-on-unknown` to treat them as errors instead.
## Documentation
For full documentation — YAML reference, usage patterns, and guides — visit **[babarot.github.io/gh-infra](https://babarot.github.io/gh-infra/introduction/getting-started/)**.
## License
MIT