An open-source, API-first source-of-truth for datacenter physical infrastructure — with an agent-driven interface.
Model the messy reality of a datacenter — devices, cabling, power, cooling, and spatial relationships across racks, rows, floors, and sites — in a strongly-consistent store, and serve it over a high-throughput gRPC API in Go. On top of that same core, a secondary MCP adapter lets anyone point their agent at it and ask questions like "what goes dark if feed B-3 trips?" and get back structured data plus a rendered diagram.
The full stack ships today: gRPC + REST + GraphQL + MCP over one Go core, OIDC/JWT auth, a read-through cache, a CHANGEFEED audit log, Prometheus/OTel observability, and container + Kubernetes manifests. Clone it, point it at your own infrastructure, and deploy it yourself — it runs locally in one command and scales out from there.
Needs Go 1.25, Docker, just, and Graphviz (brew install graphviz — the
blast-radius renderer shells out to dot).
git clone https://github.com/lex00/rackattack.git
cd rackattack
just example # build a fresh sample datacenter, open the guided-tour galleryjust example starts CockroachDB, generates a deterministic sample fleet, runs
the guided tour (all six screens, every diagram hoverable/clickable), opens
example-out/index.html, then tears the database back down — the gallery is a
self-contained artifact that survives. It also prints example prompts you can ask
an agent over MCP. To stand up a long-running instance against your own data,
rackattack serve (see Deploying below). Full walkthrough —
including the MCP and live-API paths — is in the
docs site quick start.
The conventional DCIM stack (NetBox/Nautobot) is a Django web app: a data model
plus a dense HTML frontend. rackattack keeps the hard part — an expressive,
queryable infra model behind a fast Go API — and rethinks the frontend:
- API-first, in Go. A gRPC service is the primary contract: typed, high-throughput, with complex filtering, aggregation, and bulk operations. This is the backbone and meets the role's core ask directly. (REST falls out for free via grpc-gateway when wanted.)
- An agent as the human interface. Layered on top of the same service core, an MCP adapter exposes the model to any LLM agent. Operators talk to infra conversationally; the agent composes API calls and reads back prose + diagrams. This is the differentiated layer — built last, over a contract that's already proven.
- Graphviz as the render engine. Infra is a graph. Queries render to DOT → SVG/PNG: rack elevations, cable paths, power dependency trees, thermal/blast-radius maps.
Single Go core, two transports (gRPC primary, MCP secondary), one render engine.
The DCIM market splits cleanly, and the split leaves a hole exactly where an AI cloud operates.
| Tool | Type | Strong at | API-first / automation | Built for |
|---|---|---|---|---|
| NetBox / Nautobot | OSS (Python/Django) | source of truth, cabling, IPAM | ● (REST/GraphQL, Jobs) | network automation teams |
| Sunbird dcTrack | Commercial | power and cooling, capacity | ◐ (GUI-first, 3–6 mo rollout) | enterprise / colo / hyperscale |
| Nlyte / Schneider EcoStruxure | Commercial | monitoring, analytics, BMS | ◐ | enterprise facilities ops |
| Device42 | Commercial | discovery + CMDB | ● | ITAM / ITSM orgs |
| Hyperview | Commercial (cloud) | fast rollout, monitoring | ◐ | mid-market |
| openDCIM / RackTables | OSS | basic asset + space | ○ | small shops |
Two camps, and neither fits a hyperscaler:
- Commercial DCIM (Sunbird, Nlyte, Schneider) has rich power/cooling, but is GUI-first, slow to deploy, and not automation-native.
- OSS source-of-truth (NetBox, Nautobot) is API-first and automatable, but Python/Django, network-centric, and not built for hyperscale performance.
Nobody combines an API-first source of truth + high-throughput Go + agent/MCP-native access + real power and thermal modeling. That gap is why hyperscalers (Google, Meta, AWS, and others) build this in-house: no off-the-shelf tool meets their scale, automation, and API demands at once.
rackattack is an open-source take on that in-house tool, for everyone who
isn't a hyperscaler — homelabs, colo tenants, research clusters, edge fleets,
and small clouds: the NetBox data-model idea, rebuilt as a fast Go/CockroachDB
service, with the power-and-cooling realism of a Sunbird, driven by an API (and
an agent) instead of a web GUI. Clone it, point it at your own infrastructure,
and deploy it yourself.
Who it's for, precisely: a single organization running its own fleet — one site or a handful — whose job is to communicate physical risk. Multi-tenancy and a geographic map layer are deliberate non-goals for now; the floor plan, however, is spatially representative — racks and rows carry stored positions and facing, so it reads as a walk-up map, not just a heat diagram. The persona and these scope boundaries are written up in
docs/personas-and-scope.md.
non-agent callers any LLM agent (Claude, etc.)
│ gRPC (primary) │ MCP (secondary, built last)
▼ ▼
┌──────────────────────────────────────────────────┐
│ rackattack (Go service) │
│ │
│ gRPC API ──┐ │
│ MCP tools ──┴──▶ service core │ one core,
│ - validation │ two transports
│ - complex filtering │
│ - aggregation, bulk ops │
│ graph + render (recursive → │
│ Graphviz layout → custom SVG) │
│ data access (pgx) │
└───────────────────────────┬───────────────────────┘
▼
CockroachDB
site → floor → row → rack → device
cable (graph edges, port ↔ port)
power (feed → PDU → outlet → port chain)
cooling (CRAC/CRAH → room/row → rack thermal budget)
This is the system of record for physical reality across hundreds of sites:
- Strong consistency, serializable. You cannot have split-brain about what's cabled to what or which feed powers which rack. Stale read-replica reads would be correctness bugs for an authoritative infra graph.
- Geo-distributed, survives region/AZ loss. The tooling must stay up across the same sites it models.
- Horizontal scale without manual sharding as the fleet grows.
- Postgres wire-compatible —
pgx, recursive CTEs, standard SQL all work, so no downside vs. Postgres.
For a single-node evaluation this is just "Postgres that scales out later"; the consistency and survivability properties start to matter once you run more than one node across more than one failure domain.
A typed infra graph. Core entities and the edges between them:
- Spatial hierarchy:
site → floor → row → rack → rack_unit → device. - Devices: servers, switches, patch panels, PDUs — with ports.
- Cabling:
cablerows are edges connecting two device ports (with type, length, medium). Patch panels make paths multi-hop. - Power:
feed → PDU → outlet → device power port— a dependency chain, plus redundancy (A/B feeds) so blast-radius respects failover. - Cooling / thermal (modeled for real): each device has a heat output (derived from power draw); each rack has a thermal budget; rows/rooms have CRAC/CRAH cooling capacity. This lets us compute thermal headroom and find hotspots, not just stub the concept.
- Optical transceivers: the pluggable optic in a port is a first-class entity (form factor, speed, vendor, wavelength) — one per port — so cabling and fabric reason about the optic, not just the cable medium.
A Graphviz ER diagram of the schema (and the rest of the architecture) lives in
the docs site — authored as .dot and compiled to SVG at build time,
the same diagram engine the product uses for its renders. The bigger story is how
queries are rendered — see Visualization.
Three recursive/aggregate workloads, each returning structured data and a Graphviz diagram:
- Cable-path trace. Follow a logical link end-to-end across physical hops (device port → patch panel → … → device port). Recursive CTE.
- Power-dependency rollup / blast radius. Walk feed → PDU → outlet → port to answer "if feed B-3 trips, which racks/devices lose power (respecting A/B redundancy)?" — and the inverse, "what does this device depend on?" Recursive CTE.
- Thermal headroom / hotspots. Roll device heat output up to rack and row, compare against cooling capacity, surface racks over budget.
The visualization layer is where rackattack beats the field. Not by being a prettier dashboard — by being a different kind of thing.
Update (June 2026): this stance was reversed — a web UI is being added. Live exploration (selectors: pick any feed/rack/floor and re-render) is something a class of users expects, and answer-shaped artifacts plus an agent don't fully cover it. The UI is served by the service itself (
serve→/ui, Go-rendered + HTMX) so the same surface runs local and cloud. The artifact model below still holds — generated visualizations remain the output and the export/alert format; the UI adds a live way to drive them. Rationale:docs/snapshots-and-history.md→ "Resolution".
A GUI is a persistent app you navigate — a thing to build, maintain, and learn. That's the weak part, and we cut it. A visualization is just an artifact the service renders on demand and hands back.
So the model is: the agent is the input, a generated artifact is the output. You ask a question in plain language; rackattack renders exactly the picture that answers it and returns it.
- A commercial DCIM GUI shows you a floor plan; you hunt for what you need.
- rackattack generates the diagram for your question — blast radius with only the affected racks lit red, survivors green, everything else dimmed.
The diagram is an answer, not a map. A static-GUI competitor can't do this without infinite pre-built views; rackattack gets infinite bespoke views for free, because the agent composes the query and the renderer paints the result.
Graphviz has two parts people conflate: a world-class layout engine (where do N nodes and their edges go without overlapping) and a dated renderer. We keep the first and throw away the second.
relationship graphs geometric grids
(cable path, power tree, (rack elevation,
network fabric) floor heatmap)
│ │
▼ ▼
Graphviz layout deterministic geometry
(dot -Tjson → coords) (compute x/y — it's a grid)
│ │
└──────────────┬───────────────┘
▼
ONE Go SVG painter + design system
(palette · typography · heat gradients · device
icons · semantic highlight: dead=red, survives=green)
▼
SVG (+ PNG fallback, + interactive HTML)
- Relationship visuals — Graphviz solves layout via
dot -Tjson(node positions + edge splines); our Go code paints beautiful, branded SVG from those coordinates. Auto-layout and full aesthetic control. - Geometric visuals — layout is just a grid; we compute it directly. Graphviz never touches these.
- Both feed one shared design system, so everything looks like one product.
- SVG (primary) — vector-crisp, tiny, renders inline in agent chat UIs and any browser. The everyday output.
- PNG (fallback) — for surfaces that need raster.
- Self-contained interactive HTML (wow tier) — one generated
.htmlwith the SVG embedded plus minimal vanilla JS for hover / zoom / pan / click-to-drill. A generated artifact, not a maintained app — no server, no build. The agent hands youblast-radius.htmland you explore it.
Hero mockup (hand-painted SVG) of the target render quality: Feed B-3 trips, dead racks go red, A/B-redundant racks stay green with a live feed, the rest dims. In the product this layout comes from Graphviz and is painted by the Go SVG renderer.
- Blast-radius map ⭐ (hero) — Graphviz-laid topology, custom-painted: the failed feed highlighted, dead racks red, redundant survivors green, the rest dimmed. (Stretch: animate the cascade.)
- Cable-path ribbon — elegant left-to-right flow, device cards with port pins, the traced path glowing.
- Isometric rack elevation — 2.5D racks (isometric = a 2D affine transform, no WebGL), devices as labeled slabs colored by heat or power draw.
- Floor heatmap — top-down, racks as cells colored by thermal headroom, hotspots glowing. Pure geometric SVG.
Five signature screens have approved hand-painted mockups, each with base ·
hover · select frames (hover and select are states of one interactive HTML
artifact, not separate renders — the tool call and params behind each are in
TOOLS.md). A sixth screen — the floor plan overview — is rendered
live in the guided-tour gallery (it opens the gallery) and over the FloorPlan RPC /
floor_plan MCP tool; it has no hand-painted mockup, so it isn't listed below.
Power blast radius ⭐ — "what goes dark if feed B-3 trips?"
base · hover · select
Cable path — "trace the cable path from tor-12a et-0/0/3"
base · hover · select
Rack elevation (isometric) — "show R07 by power draw"
base · hover · select
Floor heatmap — "which racks on floor 1 are running hot?"
base · hover · select
Network fabric — "where's the congestion in pod A's fabric?"
base · hover · select
Bringing your own data is the point — but an empty source-of-truth is hard to evaluate, so rackattack ships a generator and a guided tour. More than a seeder: a scale knob produces a synthetic datacenter, then it mines its own interesting scenarios, writes the prompts, runs them, and emits the diagrams — so any size of fleet produces its own narrated walkthrough. Use it to explore the model and renders against realistic sample data before wiring in your real inventory.
1. Generate a fleet (tunable, deterministic).
- Scales from one rack → row → site → multi-site
(
--sites 8 --racks-per-row 20 --oversub 3:1 --redundancy ab --seed 42). - Plausible topology: leaf-spine switching, structured cabling through patch panels, A/B power, realistic device mixes and power/heat profiles.
- Deterministic from
--seed— runs reproduce exactly (benchmarks, tests, and theexamplepreset that reproduces the walkthrough all depend on this). - Plants guaranteed-interesting scenarios: a single-point-of-failure feed, an over-budget thermal hotspot, a congested fabric uplink.
2. Take the guided tour (mine → prompt → run → render).
- Mine the interesting subjects — biggest-blast-radius feed, hottest rack, longest cable path, most-congested link.
- Prompt: template natural-language questions around them (optionally LLM-phrased for variety).
- Run: map each prompt to its tool call (TOOLS.md) and execute.
- Render: emit the diagrams into a narrated gallery — at the
examplepreset this reproduces NARRATIVE.md exactly.
In production the prompt→tool mapping is your own LLM agent over MCP; the tour driver is a scripted stand-in that exercises the pipeline without a live agent.
Used three ways: seed an instance with sample data, generate self-narrated galleries at any scale, and feed load/perf benchmarks on the hot queries.
Primary — gRPC (the product contract) — 24 RPCs in four groups:
| Group | RPCs |
|---|---|
| Queries & screens | PowerBlastRadius, TraceCablePath, GetRack, ThermalHeadroom, FabricTopology, FloorPlan, SearchDevices (paginated/filtered + counts), GetDevice, GetPort, Render |
| Mutations | Upsert/Delete × Device / Rack / Crac |
| Bulk mutations | BulkUpsert/BulkDelete × Devices / Racks / Cracs (per-item results) |
| Edge mutations | Upsert/Delete × Cable / FabricLink (keyed by endpoints) |
Each screen-generating RPC returns both structured data and a RenderResult. The
full table — request/reply shapes and the GraphQL/MCP equivalents — is on the
docs site API page.
REST is available essentially for free via grpc-gateway over the same proto,
and a GraphQL endpoint (gqlgen, schema-first) serves the screens, the
paginated/filtered device search, and the upsert/delete + bulk mutations — all
three HTTP transports resolve through the one service core (serve mounts
/graphql, /graphql/playground, and the REST gateway on the same port).
Secondary — MCP (built last): a thin adapter mapping the same service core to agent tools, so any LLM can drive the model conversationally. Not required for the gRPC story to stand on its own.
Signed OIDC/JWT bearer tokens are validated at every transport edge — a gRPC unary interceptor plus an HTTP middleware that covers both REST and GraphQL — and the resulting principal flows into a shared Authorizer that gates the surface: reads are open to any authenticated principal, while mutations and bulk operations require a writer/admin role. (Because REST and GraphQL call the service in-process, authorization lives in the wrapper they all share, not only in the gRPC chain.)
Config is environment-driven:
| Env | Meaning | Default |
|---|---|---|
AUTH_ENABLED |
turn auth on; off = dev bypass (full surface open, no token) | false |
AUTH_JWKS_URL |
OIDC JWKS endpoint for RS/ES tokens | — |
AUTH_HS256_SECRET |
configured symmetric key (use instead of JWKS) | — |
AUTH_ISSUER / AUTH_AUDIENCE |
checked against the token's iss / aud when set |
— |
AUTH_ROLES_CLAIM |
claim holding roles; dotted for nested (e.g. realm_access.roles) |
roles |
AUTH_WRITER_ROLES |
roles permitted to mutate | writer,admin |
Dev-mode bypass: with AUTH_ENABLED unset (the default), the edges inject a
dev principal carrying the writer role and the whole surface stays open — no
identity provider required, so you can evaluate locally in one command. Set
AUTH_ENABLED=true with a key source before exposing rackattack to anything you
don't fully trust.
Everything below is implemented and tested — not a roadmap.
| Area | What's there |
|---|---|
| Data model | CockroachDB schema as a typed infra graph: spatial hierarchy, cabling edges, power chains with A/B redundancy, cooling/thermal, first-class optical transceivers |
| Query workloads | PowerBlastRadius, TraceCablePath, ThermalHeadroom (recursive/aggregate CTEs), FabricTopology, FloorPlan, SearchDevices (paginated/filtered + counts) |
| APIs | gRPC (primary) · REST via grpc-gateway · GraphQL via gqlgen · MCP adapter — all over one service core |
| Mutations | Upsert/Delete for core + edge entities, BulkUpsert/BulkDelete with per-item results |
| Rendering | Custom Go SVG painter over Graphviz layout; SVG · PNG · self-contained interactive HTML; matches the approved mockups |
| Security | OIDC/JWT bearer validation + role-based authz across gRPC/REST/GraphQL |
| Caching | Read-through cache (in-process LRU or Redis) with write invalidation |
| Audit / CDC | CockroachDB CHANGEFEED → audit log + webhook sink + change-history endpoint |
| Ops | Dockerfile, k8s manifests, CI, Prometheus metrics + alerts + Grafana dashboard, OpenTelemetry traces |
| Scale | Deterministic generator to millions of rows; benchmarked hot queries; concurrent load harness |
rackattack is a single Go binary plus a CockroachDB. The fastest path:
docker compose up -d --wait # local single-node CockroachDB
rackattack serve --seed-example # auto-migrate, seed sample data, serveserve mounts gRPC, the REST gateway, GraphQL (/graphql,
/graphql/playground), and (separately) the MCP adapter. Configuration is
environment-driven (DATABASE_URL, the AUTH_* keys above, cache and telemetry
settings).
For a real deployment, deploy/ offers three paths — pick by need
(full chooser in deploy/README.md):
- Evaluation (
deploy/k8s/base, k3d) — throwaway, insecure, fastest to look at. - Minimal · single-host (
deploy/compose) — the cheapest real deploy: the whole stack on one box, secure small-prod (auth on,verify-fullDB, edge TLS, a tested backup/restore), no Kubernetes. Guide:docs/minimal-deployment.md. - Single-region production (
deploy/k8s/production) — HA, survives a node/AZ loss. Guide:docs/production-deployment.md.
Then:
- Harden it — auth (
AUTH_ENABLED=true+ a JWKS or HS256 key), CockroachDB secure (certs), TLS at the edge. The baredocker compose updefaults above are tuned for one-command local evaluation, not for exposure. - Observe it — Prometheus metrics + example alerts and a Grafana dashboard
are in
deploy/; OpenTelemetry traces span RPC → query → render.
Full instructions are on the docs site.
Issues and pull requests are welcome — bug reports, new device/topology models,
renderer improvements, and deployment recipes especially. The codebase is laid
out as cmd/rackattack + internal/{schema,gen,query,render,server} and friends;
just build / just test (the latter expects a local CockroachDB via
just up). See the contributing guide.
In one line: a Go gRPC/REST/GraphQL service on CockroachDB that models datacenter physical infrastructure — cabling, power, and cooling — as a graph, renders answers as diagrams, and lets an agent drive the whole thing over MCP.