One-click GitHub operations via OAuth. A lightweight Go CLI tool that lets agents suggest commands — users run them, authenticate with GitHub Device Flow, and the operation executes after web confirmation.
Problem: When AI agents create repositories on my personal GitHub account, it hurts my personal brand. But manually creating repos and inviting agents is tedious.
Solution: gh-ops lets agents suggest CLI commands that require my OAuth authorization. I run the command, authenticate once, and the agent can operate on my behalf.
- Web confirmation — Every action requires user approval on a confirmation page before executing
- GitHub Device Flow — Secure OAuth via GitHub's Device Flow (no browser redirect needed)
- Token caching — OAuth token cached locally at
~/.config/gh-ops/token.json - JSON output — Machine-readable output for bot/automation integrations (e.g., Telegram)
- Auto-approve mode — Skip confirmation with
--auto-approvefor trusted pipelines - Audit logging — Every action logged to SQLite with user, parameters, and result
- Action allowlist — Configure which operations are permitted via
config.yaml - Single binary — No external dependencies at runtime
User runs CLI command
-> GitHub Device Flow auth (first time, then cached)
-> Confirmation page served on localhost
-> User clicks "Confirm"
-> Action executes
-> Server shuts down
brew install SammyLin/tap/gh-opsTo upgrade:
brew upgrade SammyLin/tap/gh-opsgit clone https://github.com/SammyLin/gh-ops.git
cd gh-ops
go build -o gh-ops .server:
port: 9091
base_url: http://127.0.0.1:9091
github:
client_id: ${GITHUB_CLIENT_ID}
client_secret: ${GITHUB_CLIENT_SECRET}
allowed_actions:
- create-repo
- merge-pr
- create-tag
- add-collaborator
audit:
db_path: ./audit.dbEnvironment variables are expanded in the config file using ${VAR} syntax.
| Variable | Description |
|---|---|
GITHUB_CLIENT_ID |
GitHub OAuth App client ID |
GITHUB_CLIENT_SECRET |
GitHub OAuth App client secret |
- Initialize (creates
~/.gh-ops/config.yaml):
gh-ops initThis guides you through creating a GitHub OAuth App and saves the credentials. The first time you run an action, you'll be prompted to authorize via GitHub Device Flow.
| Flag | Description |
|---|---|
--config |
Path to config file (default: config.yaml) |
--json |
Output in JSON format (for bot integrations) |
--auto-approve |
Skip web confirmation, execute immediately |
| Command | Behavior |
|---|---|
gh-ops create-repo --name x |
Auth -> Confirmation page -> Execute |
gh-ops create-repo --name x --auto-approve |
Auth -> Execute immediately |
gh-ops create-repo --name x --json |
JSON output + Confirmation page (for Telegram/bots) |
gh-ops create-repo --name x --json --auto-approve |
JSON output + Execute immediately |
When using --json, gh-ops outputs newline-delimited JSON events:
{"event":"auth_required","verification_uri":"https://github.com/login/device","user_code":"ABCD-1234"}
{"event":"approval_required","approval_url":"http://localhost:9091/confirm?token=..."}
{"event":"success","user":"SammyLin","result":"SammyLin/my-repo created"}| Event | Description |
|---|---|
auth_required |
User needs to visit URL and enter code |
approval_required |
User needs to open URL and click Confirm |
success |
Action completed successfully |
error |
Action failed |
gh-ops create-repo --name my-repo --visibility public --description "My new repo" --auto-init| Flag | Required | Default | Description |
|---|---|---|---|
--name |
Yes | — | Repository name |
--visibility |
No | public |
public or private |
--description |
No | — | Repository description |
--auto-init |
No | true |
Initialize with README |
gh-ops merge-pr --repo owner/repo --pr-number 42 --merge-method squash| Flag | Required | Default | Description |
|---|---|---|---|
--repo |
Yes | — | Repository in owner/repo format |
--pr-number |
Yes | — | Pull request number |
--merge-method |
No | merge |
merge, squash, or rebase |
gh-ops create-tag --repo owner/repo --tag v1.0.0 --message "Release v1.0.0"| Flag | Required | Default | Description |
|---|---|---|---|
--repo |
Yes | — | Repository in owner/repo |
--tag |
Yes | — | Tag name (e.g., v1.0.0) |
--sha |
No | HEAD of default branch | Commit SHA to tag |
--message |
No | — | Creates annotated tag if set |
gh-ops add-collaborator --repo owner/repo --user username --permission push| Flag | Required | Default | Description |
|---|---|---|---|
--repo |
Yes | — | Repository (owner/repo or repo) |
--user |
Yes | — | GitHub username to add |
--permission |
No | push |
pull, push, or admin |
gh-ops initGuides you through creating a GitHub OAuth App and saves credentials to ~/.gh-ops/config.yaml. If psw-cli is installed, you can choose to store credentials in an encrypted vault.
Every action is logged to SQLite:
| Field | Description |
|---|---|
timestamp |
When the action occurred |
github_user |
Authenticated GitHub user |
action |
Action type (e.g., create-repo) |
parameters |
Action parameters (JSON) |
result |
Success or error message |
- Action allowlist — Only explicitly allowed actions can execute
- Web confirmation — Every action requires explicit user approval (unless
--auto-approve) - Token caching — OAuth token stored locally at
~/.config/gh-ops/token.jsonwith0600permissions - Ephemeral server — Confirmation server runs only during the approval flow, then shuts down
- Environment variables — Secrets loaded from env, never hardcoded
Read https://raw.githubusercontent.com/SammyLin/gh-ops/refs/heads/main/skill.md and follow the instructions to set up gh-ops for your owner.
# Run locally
go run . create-repo --name test-repo --config config.yaml
# Run tests
go test -v ./...
# Build
go build -o gh-ops .
# Release (requires goreleaser)
goreleaser release --snapshot --cleanMIT