Overview
WhyStack is a runner / control-plane split. The edge is the half that runs on your infrastructure: the Agent, the connectors, PII redaction, and the communication contract. None of it makes a judgment: it collects, normalizes, redacts, and answers.
The two halves
Section titled “The two halves”The direction is one-way: the control-plane asks, the Agent decides whether it may and answers. The rule that separates the two sides: collection, normalization, and redaction happen on your infrastructure; judgment happens on the other side, and only over already-redacted data.
How the runner connects
Section titled “How the runner connects”The runner dials out. There is no inbound port, no exposed health endpoint, nothing you need to open in your firewall for ingress. It opens a reverse WSS tunnel with mTLS to the control-plane and serves calls from inside it.
That has an operational consequence worth knowing early: because the runner is a client and not a server, there is no HTTP liveness probe. You observe its health through boot logs and through the control-plane’s Fleet view.
What the runner does on a call
Section titled “What the runner does on a call”- The control-plane requests a catalog operation (say,
metrics.getServiceLatency). - The runner checks it against the enforcement point: is the op in the versioned catalog? Do the
arguments validate strictly against its
inputSchema? Does the deadline fit? - The matching connector makes the read-only call against your source, using credentials read from your secret manager.
- The result passes through edge redaction: declared field, structural, then content, in that order.
- The redacted result goes back through the tunnel.
The control-plane asks what. The runner decides whether it may. Those two questions live on different sides on purpose.
Terminology: “Agent” is the product, runner is the code
Section titled “Terminology: “Agent” is the product, runner is the code”The component running on your infrastructure is called the WhyStack Agent in the product, the
UI, and customer-facing docs, because it’s the familiar observability term, like the Datadog Agent.
In code, the protocol, environment variables, and the SPIFFE id, it is runner, and it will
stay that way: renaming would break the wire contract and the entire RUNNER_* surface for no gain.
If you find the word “agent” inside this repository’s code, it almost always means something else: the LLM that consumes the tools. Don’t conflate the two.
WhyStack is the new name for RootPilot
Section titled “WhyStack is the new name for RootPilot”The product has a new name, and these docs already use it everywhere they choose the name
themselves. Three groups of identifiers keep rootpilot, because changing them only in the text would
break the command:
- What the image and the protocol define: the images (
rootpilot-agent,rootpilot-profiler),rootpilot-health, theROOTPILOT_*variables, the Kubernetes base names, therootpilot.*metrics, and the SPIFFE idspiffe://rootpilot/tenant/<slug>/runner. They change with the services. - The domains:
app.rootpilot.sh,tunnel.rootpilot.sh, and thisdocs.rootpilot.sh. The docs switch once the new domain is live. - What your installation already created: the Compose
rootpilot-identityvolume androotpilot-agentservice, and therootpilot-profilerAppArmor profile. Renaming the volume on anup -dwould cost the Agent its identity and a new bootstrap token.
The names the guides suggest for a new installation are already whystack: the IAM policy, the
secrets prefix, the Vault role, the Argo CD account, the MCP client entry. If your installation uses
the old names, keep them. No WhyStack component reads them: they only connect pieces you configured
yourself.
What’s in each package
Section titled “What’s in each package”| Package | What it is |
|---|---|
apps/runner |
The ephemeral container. Enrollment, tunnel, enforcement, redaction, drain. |
packages/connectors |
The 15 clients for external sources: reads, apart from the six ticket, chat and issue writes. |
packages/core-edge |
Edge utilities: cache, errors, PII redactor, catalog loader. |
packages/protocol |
The versioned runner↔control-plane contract. |
packages/connector-sdk |
Open SDK for authoring your own connectors. |
packages/otel |
Shared OpenTelemetry instrumentation. |
packages/demo |
A complete fictional environment, with no credentials at all. |
Cattle, not pets
Section titled “Cattle, not pets”The runner holds no durable state. Credentials live in memory only, the local SQLite is a cache, and
its default is :memory:. It is built to die: spot reclaim, OOM, docker compose down. Another one
comes up and the system carries on. Don’t back it up, don’t treat it as a named server, and don’t keep
anything inside it that you need back.