Self-hosting GitHub autonomy engine. A skid steer for your repos.
git-steer gives you autonomous control over your GitHub account through a Model Context Protocol (MCP) server. Manage repos, branches, security, Actions -- everything -- through natural language. Rate-limit-hardened from the ground up: ETag caching, GraphQL batching, concurrency caps, and chunked execution keep it well inside GitHub's API guardrails at any fleet size.
Passed TAEM Phase 04 gate review after two remediation cycles covering security, architecture, and test coverage.
Your machine steers. GitHub does everything else.
Nothing lives locally -- no cloned repos, no config files, no build artifacts. git-steer treats your PC or Mac as a thin control plane and GitHub as the entire runtime.
- Zero local code: No repos cloned, no
node_modules, no lock files - Keychain only: GitHub App credentials in macOS Keychain -- nothing else on disk
- Git as database: All config, state, and audit logs live in a private GitHub repo
- Actions as compute: Dependency fixes, linting, and PRs happen in ephemeral cloud runners
- Rate-limit-hardened: Throttle/retry plugins, ETag caching, GraphQL batching, concurrency caps -- safe at any fleet size
+-----------------------------------------------------------------+
| YOUR PC or MAC |
| |
| Keychain: |
| - GitHub App private key |
| - App ID / Installation ID |
| |
| $ npx git-steer (stdio -> Claude Desktop) |
| $ npx git-steer --http (portal -> localhost:3333) |
| | |
| +-> Pulls itself from ry-ops/git-steer |
| +-> Pulls state from ry-ops/git-steer-state |
| +-> Runs MCP server in-memory (rate-limit-aware) |
| +-> Commits state changes back on shutdown |
| |
+-----------------------------------------------------------------+
|
Throttled, ETag-cached,
GraphQL-batched API calls
|
v
+-----------------------------------------------------------------+
| GITHUB |
| |
| ry-ops/git-steer (source of truth for code) |
| | |
| ry-ops/git-steer-state (private repo) |
| +-- config/ |
| | +-- policies.yaml (branch protection templates) |
| | +-- schedules.yaml (job definitions) |
| | +-- managed-repos.yaml (what git-steer controls) |
| +-- state/ |
| | +-- jobs.jsonl (job history, append-only) |
| | +-- audit.jsonl (action log + rate telemetry) |
| | +-- rfcs.jsonl (RFC lifecycle tracking) |
| | +-- quality.jsonl (linter/SAST results) |
| | +-- cache.json (ETag map + sweep cursor) |
| +-- .github/workflows/ |
| +-- heartbeat.yml (scheduled triggers) |
| |
+-----------------------------------------------------------------+
The MCP server is split into per-domain tool modules under src/mcp/tools/. Each module exports getTools() (tool definitions) and handleCall() (tool execution). The server collects tools from all modules at startup and dispatches via a name-to-handler map.
src/mcp/
+-- server.ts # MCP protocol, transport init, tool dispatch (~600 lines)
+-- permissions.ts # Destructive tool registry, dry-run defaults
+-- tools/
+-- index.ts # Re-exports all domain modules
+-- types.ts # Shared ToolDeps interface
+-- repos.ts # Repository management (8 tools)
+-- branches.ts # Branch operations (3 tools)
+-- prs.ts # Pull request workflows (3 tools -- was 5 with dedup)
+-- security.ts # Security scanning and sweeps (7 tools)
+-- actions.ts # GitHub Actions (3 tools)
+-- ops.ts # Observability, config, reports (8 tools)
+-- k8s.ts # Kubernetes ops (4 tools, conditional)
+-- misc.ts # Slack, code review, quality (5 tools)
Fabric tools (CVE pipeline and git operations) are defined in server.ts and delegated to @git-fabric/cve and the FabricGitHubAdapter at runtime.
All modules receive a ToolDeps bag containing the GitHub client, state manager, gateway handle, rate limit helpers, and concurrency limiters -- no direct imports of shared state.
42 core tools + 20 fabric tools, organized by domain.
| Tool | Description |
|---|---|
repo_list |
List all accessible repositories |
repo_create |
Create new repo (optionally from template) |
repo_archive |
Archive a repository (destructive) |
repo_delete |
Permanently delete a repository (destructive) |
repo_scrub_history |
Rewrite repo history to remove sensitive data (destructive) |
repo_settings |
Update repo settings (visibility, features, merge options) |
repo_commit |
Commit files directly via GitHub API (no local clone) |
repo_read_file |
Read a file from a repository (ETag-cached) |
repo_list_files |
List files in a directory |
| Tool | Description |
|---|---|
branch_list |
List branches with staleness info (GraphQL-batched) |
branch_protect |
Apply protection rules |
branch_reap |
Delete stale/merged branches (destructive, dry-run default) |
| Tool | Description |
|---|---|
pr_dedup_check |
Check if a PR already exists for a branch |
pr_dedup_create |
Create PR only if one doesn't already exist |
| Tool | Description |
|---|---|
security_scan |
Scan repos for vulnerabilities with fix info |
security_alerts |
List Dependabot/code scanning alerts |
security_digest |
Summary across all managed repos |
security_sweep |
Full autonomous pipeline: scan, RFC, fix PR, track (dry-run default) |
security_fix_pr |
Dispatch workflow to fix vulnerabilities (dry-run default) |
security_dismiss |
Dismiss alert with reason (destructive) |
security_enforce |
Ensure Dependabot alerts + automated fixes are enabled |
| Tool | Description |
|---|---|
actions_workflows |
List workflows |
actions_trigger |
Manually trigger a workflow |
actions_secrets |
Manage Actions secrets |
| Tool | Description |
|---|---|
config_show |
Display current config |
config_add_repo |
Add repo to managed list (auto-enables Dependabot) |
config_remove_repo |
Remove from managed list |
steer_status |
Health check with full rate limit budget |
steer_sync |
Force save state to GitHub |
steer_logs |
View audit log with rate limit telemetry |
ops_metrics |
Operational metrics and statistics |
dashboard_generate |
Interactive security dashboard, deployed to GitHub Pages |
report_generate |
Compliance reports (executive summary, change records, vulnerability, full audit) |
Only registered when kubectl is on PATH. Not visible in ListTools otherwise.
| Tool | Description |
|---|---|
oomkill_detect |
Detect OOMKill events in the cluster |
oomkill_remediate |
Adjust resource limits for OOMKilled pods (dry-run default) |
cert_check |
Check TLS certificate expiry |
cert_renew |
Renew TLS certificates (destructive) |
code_review only registered when the cr (CodeRabbit) binary is on PATH.
| Tool | Description |
|---|---|
slack_notify |
Send a Slack notification |
slack_configure |
Configure default Slack webhook |
code_quality_sweep |
Run linters/SAST via GitHub Actions |
code_review |
AI-powered code review via CodeRabbit CLI (conditional) |
workflow_status |
Check status of dispatched workflows |
| Tool | Description |
|---|---|
fabric_cve_scan |
Scan managed repos against GitHub Advisory Database |
fabric_cve_enrich |
Fetch enriched CVE details from NVD |
fabric_cve_triage |
Process pending CVE queue: apply policy, open PRs |
fabric_cve_queue |
List CVE queue entries by status/severity |
fabric_cve_stats |
CVE queue health dashboard |
fabric_cve_compact |
Compact resolved entries from the queue |
14 tools for direct GitHub operations (fabric_git_list_repos, fabric_git_get_file, fabric_git_commit_files, fabric_git_list_commits, fabric_git_get_commit, fabric_git_compare_commits, fabric_git_list_branches, fabric_git_create_branch, fabric_git_delete_branch, fabric_git_list_files, fabric_git_list_pull_requests, fabric_git_get_pull_request, fabric_git_create_pull_request, fabric_git_merge_pull_request).
Tools classified as destructive require an explicit confirm parameter set to CONFIRM_<TOOL_NAME> (e.g., CONFIRM_REPO_DELETE). Without it, the tool returns a warning and takes no action. Destructive tools: repo_delete, repo_archive, repo_scrub_history, branch_reap, cert_renew, security_dismiss.
Sweep and remediation tools default to dry_run: true when the caller does not set it explicitly. This means an LLM cannot accidentally trigger writes without intent. Affected tools: security_sweep, security_fix_pr, branch_reap, oomkill_remediate.
The FabricGitHubAdapter interface exposes a headers() method that returns pre-built Authorization headers. The raw token is never visible to callers -- it stays private inside the adapter implementation. The gateway no longer writes tokens to process.env.
Slack webhook URLs are validated against an allowlist (hooks.slack.com, hooks.slack-gov.com). Arbitrary URLs are rejected.
K8s tools (oomkill_detect, oomkill_remediate, cert_check, cert_renew) are only registered when kubectl is found on PATH. code_review is only registered when the cr binary is available. Tools that cannot execute are not advertised.
# First time setup
npx git-steer init
# This will:
# 1. Create a GitHub App with required permissions
# 2. Install it to your account
# 3. Create a private git-steer-state repo
# 4. Store credentials in macOS Keychain
# Start the MCP server
npx git-steerAdd to ~/Library/Application Support/Claude/claude_desktop_config.json:
{
"mcpServers": {
"git-steer": {
"command": "npx",
"args": ["git-steer"]
}
}
}Or use a local checkout:
{
"mcpServers": {
"git-steer": {
"command": "node",
"args": ["/path/to/git-steer/bin/cli.js", "start", "--stdio"]
}
}
}git-steer includes an HTTP/SSE transport mode that exposes the MCP server as a local web portal:
git-steer start --http # Default port 3333
git-steer start --http --port 8080 # Custom portEndpoints: /dashboard (live security dashboard), /mcp (Streamable HTTP, protocol 2025-11), /sse + /messages (legacy SSE, protocol 2024-11), /health (JSON status).
The portal uses the same Keychain credentials, same state repo, and same rate-limit-hardened API stack as stdio mode.
Seven-layer API safety stack:
- Throttle/Retry -- Primary (429) auto-retry up to 4x, secondary (403) always back off, transient 5xx exponential backoff
- Concurrency caps -- Writes max 2, reads max 8, search serial (via p-limit)
- ETag caching -- Contents API sends If-None-Match, 304 avoids rate cost, persisted across restarts
- GraphQL batching -- Owner resolution, branch listing, Dependabot alerts batched into single calls
- Rate budget visibility --
steer_statusshows all buckets with % remaining, warns below 15% - Audit telemetry -- Every action logged with rate_remaining, retry_count, backoff_ms
- Chunked sweep --
security_sweep(chunkSize: 10)processes in batches, cursor persisted forresume: true
42 tests passing across 7 test files. Vitest with v8 coverage provider, 60% floor on lines/functions/statements, 50% on branches.
npm test # Run all tests
npm run test:coverage # Run with coverage report- Repository: Read & Write (contents, metadata)
- Pull Requests: Read & Write
- Issues: Read & Write (for RFC tracking)
- Actions: Read & Write (for workflow dispatch)
- Dependabot alerts: Read & Write
- Code scanning alerts: Read
- Secrets: Read & Write (for Actions secrets)
- Administration: Read & Write (for repo settings)
- Pages: Read & Write (for dashboard deployment)
git-steer init # First-time setup
git-steer # Start MCP server via stdio (Claude Desktop)
git-steer start --http # Start local portal on port 3333
git-steer start --http --port 8080 # Start portal on custom port
git-steer scan # Run security scan across all repos
git-steer scan --repo owner/name # Scan a specific repo
git-steer scan --severity critical # Filter by severity
git-steer status # Show status + rate limit budget
git-steer sync # Force sync state to GitHub
git-steer reset # Remove local credentialsMIT
Built by ry-ops