Files
hanzo.ai/app/(marketing)/telemetry/page.tsx
zooqueen 75c4f1f641 One product answers with one name, route, command and docs page
The CLI lines on the product pages were written from the product name -- hanzo
dns zones, hanzo kms keys -- and several were not commands the binary has. So the
command moves into lib/product.ts, which assembles the rest from what is already
stated: the catalog names the product and its route, pages.json names what the
catalog does not carry, and products-metadata answers for docs, where null means
docs publishes nothing and the link drops.

Every CLI line in that table was run against the binary. A product absent from it
has no command and its page prints none; nothing composes a verb out of a name.
Both blocks that draw it import the Product type rather than declaring their own,
which leaves the table the only place a command can be written.

The catalog also moves out of package.json into pnpm-workspace.yaml, where pnpm
reads it, so the versions are stated once.
2026-09-06 23:18:24 -07:00

80 lines
3.6 KiB
TypeScript

'use client'
import { ArrowRight, Activity, Cable, Filter, Globe, Layers, Shield, Zap } from 'lucide-react'
import { ProductLanding } from '@/components/product/ProductLanding'
import { ProductFooter } from '@/components/products/ProductFooter'
/**
* Hanzo Telemetry, through the ONE product kit.
*
* The largest cluster left: TWELVE pages — engine, gateway, guard, ingress,
* jin, metrics, o11y, operator, sentinel, skills, telemetry, visor — at 85%+
* identical className sets, each a hero, a six-card grid and a call to action
* written out again. All twelve pass one typed props object to
* `ProductLanding`. See LLM.md, "Tailwind is NOT gone".
*
* EVERY WORD IS THE ONE THAT WAS HERE. ProductFooter came out of the final
* card's `max-w-3xl` wrapper, where it had been rendering narrower than on
* every other product page.
*/
export default function HanzoTelemetryPage() {
return (
<>
<ProductLanding
badge={"telemetry.hanzo.ai"}
badgeIcon={Activity}
title={"Hanzo Telemetry"}
tagline={"The collector that sits between your app and wherever the data goes"}
lede={"Your services talk to it instead of talking to a backend. It receives OTLP, batches it, holds a memory ceiling so a traffic spike cannot take the host down with it, and forwards onward. Change where the data goes by editing its config — not by redeploying every service that produces the data."}
ctas={[
{ label: "View on GitHub", href: "https://github.com/hanzoai" },
]}
what={{
title: "One hop you control",
sub: "The last place your telemetry is yours before it goes anywhere.",
pillars: [
{
icon: Cable,
title: "OTLP in, OTLP out",
body: "Receives over gRPC and HTTP, exports the same way. OTLP is the format the OpenTelemetry SDKs already speak, so nothing in your code changes to point at it.",
},
{
icon: Layers,
title: "Traces, metrics and logs",
body: "All three move through the same process, so there is one thing to run, one config to read and one place to look when telemetry stops arriving.",
},
{
icon: Filter,
title: "Batching",
body: "Spans arrive one at a time and leave in batches. That is the difference between a request per span and a request per few thousand, and your backend feels it.",
},
{
icon: Zap,
title: "A memory ceiling",
body: "Tell it how much memory it may use and it refuses work rather than exceeding it. Telemetry is the thing that should degrade during an incident, not the thing that causes one.",
},
{
icon: Globe,
title: "Assembled, not installed",
body: "This is the collector itself. Build a distribution with the receivers, processors and exporters you actually want, and ship one binary containing those and nothing else.",
},
{
icon: Shield,
title: "It runs where you run",
body: "A binary in your own network. Whatever you decide not to forward, you decide before the data has left — which is the only point where that is still your call.",
},
],
}}
finalCta={{
title: "Put it in front of your backend",
buttons: [
{ label: "View on GitHub", href: "https://github.com/hanzoai" },
],
}}
/>
<ProductFooter slug={"telemetry"} name={"Telemetry"} />
</>
)
}