git-steer started as a lean MCP orchestrator for GitHub. Repos, branches, PRs, Actions — the control plane for everything on my account. Then CVE scanning landed. Then enrichment. Then triage logic, queue management, compaction, batch operations. Before I noticed, src/fabric/cve.ts was 558 lines long, with another 163 in src/fabric/adapter.ts. Seven hundred and twenty lines of domain-specific security logic living inside something that was supposed to be a thin orchestration layer.
Every fix had to land in two places. Every feature was wired twice. And the worst part: the code was good. It worked. It just didn’t belong there.
The extraction
The answer wasn’t “refactor git-steer.” It was “extract the domain.”
CVE detection-to-remediation is its own problem space with its own lifecycle. It has scan logic, intelligence enrichment, triage decisions, remediation actions, and persistent state. That’s not a feature of an MCP orchestrator — that’s a standalone application that an orchestrator should consume.
So I pulled it out. Not into a library, not into a shared module — into a completely separate application with its own repo, its own tests, its own release cycle. And once I had one extracted app, the question became obvious: what connects them?
That’s git-fabric.
What git-fabric is
git-fabric is a GitHub org of composable fabric apps for Git-native infrastructure. Each app owns one domain end-to-end. A gateway aggregates them into a single MCP surface. Consumers — git-steer, Claude Desktop, GitHub Actions, whatever speaks MCP — connect once and access everything.
Consumer (git-steer, Claude Desktop, Actions)
|
v
Gateway ── registers ──> @git-fabric/cve
── registers ──> @git-fabric/??? (next app)
── registers ──> @git-fabric/??? (future)
The gateway is a tool aggregator. Apps register themselves, declaring their tools and the adapter interfaces they need. The gateway exposes all registered tools through one unified surface. A consumer connects to the gateway once, gets a merged tool list, and routes calls transparently.
Architecture of a fabric app
Take @git-fabric/cve, the first app. It has five layers:
- Detection — Scan repos for Dependabot alerts and CodeQL findings
- Intelligence — Enrich raw alerts with NVD data, EPSS scores, fix availability
- Decision — Triage based on severity, exploitability, exposure
- Action — Batch remediation, PR creation, workflow dispatch
- State — Persistent queue with compaction, stats, filtering
Each layer calls the next. The whole pipeline exposes 8 MCP tools: cve_scan, cve_enrich, cve_batch, cve_triage, cve_queue_list, cve_queue_stats, cve_queue_update, and cve_compact.
The app doesn’t know or care who’s calling it. It defines adapter interfaces — “I need something that can read GitHub alerts” and “I need something that can commit files” — and the consumer provides implementations. The CVE app never imports Octokit directly. It declares what it needs; the adapter wires the implementation.
Design principles
These aren’t aspirational. They’re the constraints that shaped the code.
One app, one domain. CVEs are one app. Compliance would be another. Drift detection another. No app touches a domain that isn’t its own.
Adapter interfaces. Apps declare what they need; consumers provide implementations. @git-fabric/cve works the same whether it’s called from git-steer, Claude Desktop, or a GitHub Action.
Layers, not monoliths. Every app is a pipeline. Detection doesn’t know about remediation. Triage doesn’t know about scanning. Test, replace, or extend any layer independently.
MCP-native. Every app exposes its functionality as MCP tools. No REST APIs, no GraphQL schemas. MCP is the interface contract.
Zero coupling between apps. Removing one app doesn’t break another. The gateway handles presence and absence gracefully — if an app isn’t registered, its tools simply don’t appear.
What’s shipping today
Two packages:
@git-fabric/cve — The CVE detection-to-remediation fabric app. Everything that was inline in git-steer, properly extracted with a createApp() factory, clean adapter interfaces, and hardened Octokit with throttling and retry plugins. Five layers, eight tools, full test coverage.
@git-fabric/gateway — The tool aggregator. Register apps, expose tools, route calls. The integration with git-steer replaced 720 lines of inline code with a 65-line gateway module. The routing just works.
What’s next
The gateway is ready for N apps. The infrastructure cost of adding a new domain is: write the app, call gateway.register(), done.
Compliance reporting is a strong candidate — it has a clear lifecycle (scan, evaluate, report, remediate) that maps to the layer pattern. Drift detection is another. But I’m not going to build them until I need them. git-fabric exists because 720 lines of CVE code in an MCP orchestrator was a real problem, not because I wanted an org with a lot of repos. The next app ships when the next domain earns its extraction.
Organization: github.com/git-fabric
CVE App: github.com/git-fabric/cve
Gateway: github.com/git-fabric/gateway
Questions, issues, or ideas for the next fabric app? Open an issue on the relevant repo or start a discussion at the org level.