Skip to content
Agentmart
Submit a tool

CLAUDE.md · skyhook-io/radar

CLAUDE.md from skyhook-io/radar: 272 lines covering Project Overview, Code comments, Release and publishing authorization, Reference Docs — MUST READ before…

Template by skyhook-io

IndexedApache-2.0★ 3,906
Write a review

Install

Works with Claude Code. Read the repository before you give any tool access to your data.

curl -fsSL https://raw.githubusercontent.com/skyhook-io/radar/main/CLAUDE.md -o CLAUDE.md

Read it and adapt it to your project before use.

Get the weekly diff

The weekly diff: one email a week with new agent tools, notable updates and grade changes, plus security alerts for tools you follow. Double opt-in, one-click unsubscribe.

We use your email only for this newsletter. Privacy

About

The CLAUDE.md file that skyhook-io/radar (3,905 stars) keeps for coding agents. It has 272 lines in 11 sections: Project Overview; Code comments; Release and publishing authorization; Reference Docs — MUST READ before making changes; Library distribution; Architecture; Project Structure; Development Commands; API Endpoints & CLI Flags; Key Patterns; Tech stack + server config. Use it as a model for your own project's instructions.

Use cases: prompt-engineering

No reviews yet. Installed it? Reviews come from verified installers only. How reviews work

What's in it

A CLAUDE.md file: project memory Claude Code loads at the start of every session.

For
Claude Code
Length
272 lines
File
CLAUDE.md

Sections

  1. Project Overview
  2. Code comments
  3. Release and publishing authorization
  4. Reference Docs — MUST READ before making changes
  5. Library distribution
  6. Architecture
  7. Project Structure
  8. Development Commands
  9. API Endpoints & CLI Flags
  10. Key Patterns
  11. Tech stack + server config

First lines (shown under the repo's Apache-2.0 license)

# CLAUDE.md

## Project Overview

Radar is a modern Kubernetes visibility tool — local-first, no account required, no cloud dependency, fast. It provides topology visualization, event timeline, service traffic maps, resource browsing, Helm management, cluster audit (best-practices scanning), and Kubernetes upgrade impact analysis. Runs as a kubectl plugin (`kubectl-radar`) or standalone binary and opens a web UI in the browser. Open source, free forever. Built by Skyhook.

## Code comments

- Default to writing no comments. Only add one when the WHY is non-obvious — a hidden constraint, a subtle invariant, a workaround for a specific bug, or behavior that would surprise a reader.
- Don't explain WHAT the code does — well-named identifiers already do that.
- **Don't reference tickets, PRs, bug numbers, or diff history** in code comments (e.g. "fixes SKY-123", "Bugbot caught this on PR #584", "used to read X, now…"). Those belong in the PR description and rot as the codebase evolves. The WHY of the change should stand on its own.
- This applies to comments written by any tool (Cursor, Bugbot, Copilot) as well as humans — strip ticket/PR references before merging.

## Release and publishing authorization

- Never create, move, or delete Git tags or GitHub Releases; dispatch release or publish workflows; or publish binaries, container images, npm packages, package-manager artifacts, Helm charts, or other distribution artifacts without explicit user approval naming the exact artifact, version, and action.
- Approval to implement a change, open or merge a PR, or prepare release changes is not authorization to publish. If release authorization is ambiguous, stop and ask.

## Reference Docs — MUST READ before making changes

Not everything is in this file. The following files contain critical details that are **not duplicated here** — this file keeps the cross-cutting rules; per-area depth (gating rationale, lifecycle rules, scope semantics) lives in the files below. You MUST read the matching row's files **before editing** in that area — do not guess or rely on memory. If your area has no row, the handler's or package's own doc comments are the spec; read them first.

| When you are... | Read this file FIRST |
|-----------------|---------------------|
| Preparing, editing, auditing or previewing **What's New** release notes | [.agents/skills/whats-new/SKILL.md](.agents/skills/whats-new/SKILL.md) — merged-work buckets, copy, scoring, preview, and opt-in docs/marketing changelog checks with safe sibling/worktree handling |
| Adding or modifying **HTTP endpoints** | `internal/server/server.go` — all routes are defined here — **plus** the handler's doc comments (why the route is gated the way it is lives there; copy the gate of the closest sibling only after reading it) and the integration's section in [docs/integrations.md](docs/integrations.md) |
| Adding or modifying **CLI flags** | `cmd/explorer/main.go` — flag definitions and defaults |
| Adding a **new CRD integration** (renderer, topology, discovery) | [docs/INTEGRATION_GUIDE.md](docs/INTEGRATION_GUIDE.md) — full checklist with collision gotchas |
| Building a **workspace integration** (several related CRDs with their own screens, like `/cnpg` or `/capacity`) | [docs/INTEGRATION_GUIDE.md](docs/INTEGRATION_GUIDE.md#3-workspace-integrations) — the shared server, UI and action pieces to import, and what is not shared yet; [DESIGN.md](DESIGN.md#unknown-partial-and-denied-values) — how unknown, partial and denied values read |
| Working on the **CloudNativePG workspace** (`/cnpg`) | [docs/cnpg.md](docs/cnpg.md) — destinations, navigation (drawer trail, return label, `ctx` guard) and the certainty table: which source each fact comes from and what it reads when unknown. Data from `/api/cnpg/workspace` (per-kind coverage); derivations in `packages/k8s-ui/src/components/cnpg/workspace.ts` + `relations.ts`; screens in `web/src/components/cnpg/` |
| Working on **local per-cluster integration settings** (Metrics, Argo CD, Cost in `~/.radar/clusters.json`) | [docs/configuration.md](docs/configuration.md#local-integration-connections) — store `internal/config/profiles.go`, resolve/update `internal/connections`, activation `internal/connectionruntime`, routes `GET/PUT /api/integrations/connections`. In local mode the older `PUT /api/integrations/{prometheus,argocd,cost}` return 409 |
| Working on **GitOps** (Argo CD / Flux detail pages, operations, Terminating lifecycle, drift, per-resource health, remote destinations) | [docs/gitops.md](docs/gitops.md) — detail-page tabs, operation semantics, the Terminating severity ramp, nested navigation, single-cluster scope. Engine in `pkg/gitops/`, handlers `internal/server/gitops_handlers.go` |
| Working on an **integration's reverse-lookup or actions** (Velero, CloudNativePG, Kyverno, Argo Rollouts, …) | That integration's section in [docs/integrations.md](docs/integrations.md) + the doc comments in `internal/server/<name>_handlers.go` — both carry the per-integration gating and scope rules this file only summarizes |
| Working on **RBAC visibility** (Permissions / blast radius, SA/Role/Binding reverse lookups) | `pkg/rbac/index.go` (index, implicit groups, `MaxFlatRules`), `internal/server/rbac_handlers.go`, and the header of `packages/k8s-ui/src/utils/rbac-blast-radius.ts` — the rule that resource-only wildcards must NOT trigger is load-bearing |
| Working on **SSE / live updates** or anything the **topology** emits to a browser | `Server.handleSSE` in `internal/server/server.go` (per-user filtering), `internal/server/sse.go` (per-client RBAC grouping, `clientCanSeeChange`) + `pkg/topology/cluster_scoped_kinds.go` |
| Working on **ownership** (owner references, dependents, GitOps managers' recorded members, the manager answer, the ownership oracle) | [docs/ownership.md](docs/ownership.md) — the evidence model (owner references, recorded membership, claims), which wire field answers which question, the manager answer, coverage and completeness, and the oracle every change is checked against; contract in `pkg/ownership`, indexes in `pkg/k8score/owner_index.go` + `gitops_members_index.go` |
| Working on the **informer cache** (new typed kind, field stripping, scope) | `pkg/k8score/cache.go` + `pkg/k8score/transform.go` (what is stripped and why), `internal/k8s/capabilities.go` (probe-based scope) |
| Working on the **timeline / workload history** | `pkg/timeline/store.go` (`ResourceScope`: owner UID, `OwnerlessRefs`) + the `handleWorkloadHistory` doc comment in `internal/server/workload_history.go` |
| Working on **network trace / reachability** | [docs/reachability.md](docs/reachability.md) + `internal/server/trace_handlers.go` |
| Working on **authentication, auth-enabled mode, impersonation or per-user authorization** | [docs/authentication.md](docs/authentication.md) — auth modes, how per-user RBAC is enforced, ServiceAccount RBAC, session cookies. For Radar Cloud's default permission tiers and the integration-read policy, [docs/cloud-rbac-baseline.md](docs/cloud-rbac-baseline.md) |
| Changing the **Helm chart** or **in-cluster deployment** (chart values, chart RBAC, ingress) | [deploy/helm/radar/README.md](deploy/helm/radar/README.md) — the canonical chart source (the `skyhook-io/helm-charts` copy is overwritten on release, never edit it there); [docs/in-cluster.md](docs/in-cluster.md) for deployment paths |
| Working on the **Helm releases view** (release list, revisions, rollback, operation insight) | [docs/helm.md](docs/helm.md) |
| Working on the **Metrics tab** (workload HTTP rate/errors/latency, CPU/memory/throttling) | [docs/workload-metrics.md](docs/workload-metrics.md) — metric sources, attribution, per-run-mode overrides; test with `make workload-metrics-demo` |
| Working on **application grouping** ("these workloads are one app", cross-cluster app identity) | [docs/app-grouping.md](docs/app-grouping.md) — the model, then the code files it names |
| Touching **usage stats / telemetry** | [docs/usage-stats.md](docs/usage-stats.md) — it is a public promise of what is and isn't collected; a change that breaks it breaks the promise |
| Working on **performance at high object counts** | [docs/loadtest.md](docs/loadtest.md) — synthetic fake-cluster UI load testing |
| Working on the **Capacity (Karpenter) views** | [docs/capacity.md](docs/capacity.md) — the four screens, the per-value certainty contract (`= ≥ ≤ ?`, unavailable ≠ zero, partial ≠ exact, declared ≠ actual), demand-evaluation semantics, and the real Karpenter failure model. Wire types in `pkg/capacityapi`, engine in `internal/capacity`, handlers in `internal/server/capacity*` |
| Working on **Node status or removal diagnostics** | [docs/nodes.md](docs/nodes.md) — cross-surface contract; policy in `pkg/health/node_lifecycle.go`, raw-node UI mirror in `packages/k8s-ui/src/utils/node-lifecycle.ts`, shared vectors in `pkg/health/testdata/node_lifecycle.json` |
| Working on **resource renderers** | `packages/k8s-ui/src/components/resources/renderers/` — all existing renderers live here |
| Understanding **cluster connection behavior** or the **namespace picker** | [docs/configuration.md](docs/configuration.md) — kubeconfig precedence, multi-context, in-cluster, and the Namespace Picker section (persistence, kubectl-parity default, `--namespace-scope`) |
| Working on **MCP tools or AI context** | [docs/mcp.md](docs/mcp.md) + `internal/mcp/tools.go` — tool definitions and design rationale |
| Reporting **what an answer covers** — partial, unknown, denied or not-collected results on any surface (REST, MCP, search, change history) | [docs/mcp.md](docs/mcp.md#resource-reads-coverage-and-errors) — codes and their actions in `pkg/readreason` (mirrored in `packages/k8s-ui/src/utils/read-actions.ts`), coverage types in `pkg/resourceapi`, per-namespace collection planning in `internal/readplan`; search's assembly in `internal/search` is the multi-kind example. Reuse these rather than adding a parallel vocabulary. Time is separate: since when Radar holds history is `issuesapi.HistoryCoverage` |
| Working on the **investigation verdict, story or Findings pane** | [docs/mcp.md](docs/mcp.md) ("The story contract") — the verdict JSON, `[[radar:evidence=N]]` placement grammar, run-scoped citation, and the assessment-turn rule. The contract (prompts, verdict, parser, binder) lives in `pkg/investigation`, **shared with Radar Hub**; OSS orchestration and ref eligibility stay in `internal/ai/runs.go`; frontend in `web/src/components/diagnose/` (`investigationStory.ts`, `AnalysisStory.tsx`, `investigationState.ts`) |
| Writing or modifying **frontend UI / styling** | [DESIGN.md](DESIGN.md) — theme tokens, do's/don'ts, component patterns |
| Syncing k8s-ui to **Claude Design** (`/design-sync`) | [.design-sync/NOTES.md](.design-sync/NOTES.md) + [.design-sync/conventions.md](.design-sync/conventions.md) (the usage guide shipped to Design) — build pipeline (`build-pkg.mjs`), config, re-sync command, known warns and size budget. `.design-sync/previews/*.tsx` are the authored preview cards; update them when a previewed component's props change |
| Touching anything library consumers import | `web/package.json` + `web/src/index.ts` (and the consumer-facing `web/README.md` / `packages/k8s-ui/README.md` — e.g. the k8s-ui YAML editors must stay CDN-free for air-gapped installs) — `web/` IS the `@skyhook-io/radar-app` npm package. Public surface: `RadarApp`, runtime-config setters (`setApiBase` etc.), `NavCustomization`. Breaking it breaks all downstream consumers. |
| Adding or changing **api/fetch call sites** | `web/src/api/config.ts` — all fetches go through `getApiBase()`, `apiUrl()`, `getWsUrl()`, `getAuthHeaders()`, `getCredentialsMode()`. New fetch sites must use these helpers so library consumers (Radar Hub) can override per-cluster. |
| Embedding Radar inside another app | `web/src/RadarApp.tsx` + `web/src/context/NavCustomization.tsx` — `apiBase`, `basename`, `router`, `navSlots` props. Check Radar Hub call sites when changing this interface. |

## Library distribution

Radar's frontend is also published as **`@skyhook-io/radar-app`** (source-only npm package, same model as `@skyhook-io/k8s-ui`). `web/` IS the package — `web/src/index.ts` is the library entry, and Radar's own binary entry (`web/src/main.tsx`) consumes the same source. Consumers get `<RadarApp apiBase basename router navSlots queryClient />`, the runtime-config setters (`setApiBase`, `setBasename`, `setAuthHeadersProvider`, `setCredentialsMode`) for non-React code paths, and the `NavCustomization` type. Published via tag `radar-app-v<semver>` (`.github/workflows/publish-radar-app.yml`) — only with explicit authorization, per the rule above.

Known consumers: Radar Hub (`skyhook-dev/radar-hub-web`).

`pkg/` is a separate Go module (`github.com/skyhook-io/radar/pkg`) that Radar Hub imports (`issuesapi`, `investigation`, `k8score`, `checks`, `auth`, …): keep it free of `internal/` imports and coordinate exported-API changes with Hub, same as the npm packages.

**Consumer scope:** Radar OSS and Radar Hub are the supported consumers. Coordinate interface changes with Hub; do not preserve unused modes or add migration machinery for hypothetical consumers. `navSlots.embedded` hides all Radar chrome; Hub owns its sidebar and top bar.

## Architecture

A single Go binary talks directly to the Kubernetes API through kubeconfig (`~/.kube/config`) or the in-cluster ServiceAccount — there is no Radar backend service in between. The same process serves the embedded React UI (HTTP/SSE/WebSocket) and AI tools over MCP (`/mcp`).

## Project Structure

See [docs/STRUCTURE.md](docs/STRUCTURE.md) for the full directory map + tech-stack snapshot. The load-bearing concerns (caching, topology, MCP, error handling, renderers) have their own sections below — the directory tree exists to orient, not to drive behavior.

## Development Commands

### CRITICAL: Frontend Embedding Pipeline

The Go binary serves the frontend via `go:embed` from `internal/static/dist/`, NOT from `web/dist/`. The build pipeline is:

```
web/src → (npm run build) → web/dist → (make embed) → internal/static/dist → (go build) → binary
```

**ALWAYS use `make build` to build the full application.** Running `cd web && npm run build` followed by `go build` will NOT update the served frontend — the embed step (`make embed`) that copies `web/dist/*` to `internal/static/dist/` will be skipped, and the binary will serve stale frontend assets.

### Build / test / run

`make help` lists every target — read the Makefile when uncertain. The day-to-day set: `make build` (frontend + embed + binary), `make restart` (full rebuild + restart) / `make restart-fe` (frontend + embed + restart), `make watch-backend` / `make watch-frontend` (Air :9280 + Vite :9273), `make test`, `make tsc`, `make lint` (`go vet` on both Go modules, the root and `pkg/`). `go run ./cmd/explorer --dev` serves the frontend from `web/dist` without the embed step. Web unit tests: `cd web && npm test`; the Playwright specs in `web/e2e` run separately (`npm run test:e2e:settings`).

**Fast dev loop above all.** While iterating, run `make test-changed` (only the changed Go packages, tsc, and `vitest related` for changed frontend files) once per batch of fixes, not a full suite per edit. The full run happens once at the end, and CI on the pushed head is that run; run the full suite locally only for a branch CI won't test, such as a stacked PR. Don't run suites alongside other heavy work; a failure in an untouched file under load gets rerun alone before anyone debugs it. Details: `.claude/commands/qa.md`.

### Visual Testing
```bash
./scripts/visual-test-start.sh          # Build + launch on random port (9300-9399)
./scripts/visual-test-start.sh --skip-build  # Relaunch without rebuilding
source .playwright-mcp/visual-test-state.env # Load $RADAR_URL, $SCREENSHOT_DIR, etc.
./scripts/visual-test-stop.sh           # Kill process, open screenshot folder
```
Use `/visual-test` command for the full workflow (cluster check, Playwright MCP, screenshots, report). Screenshots go under `.playwright-mcp/visual-test/`.

### Demo clusters (scripted test fixtures)

Scripted `kind` clusters under `scripts/*-demo.sh` reproduce the states each integration needs — states that are hard or impossible to conjure by hand (frozen controllers holding all phases at once, configurations that fail in ways that look like success, connection lanes toggled on demand).

**Before using one, read its `scripts/<name>-demo/README.md` — this is not optional.** Each README is the only complete account of what the scenarios cover, which modes are NOT interchangeable, and why the cluster is shaped the way it is; the shape encodes hard-won constraints that look like bugs if you don't know them. Don't improvise against the fixtures or "fix" what looks broken before reading it.

After `make <name>-demo`, run `kubectl config use-context kind-radar-<name>-demo` before `./scripts/visual-test-start.sh` — otherwise you're testing against whatever cluster the current context points at (often a customer cluster lacking the fixture variety).

| Demo | Target | Use when working on |
|------|--------|---------------------|
| GitOps | `make gitops-demo` | Argo CD / Flux UI. `-drift` induces live OutOfSync |
| Kyverno | `make kyverno-demo` | Policy renderers, report-family selection, admission attribution. Scenarios `openreports` / `modern-only` |
| Velero | `make velero-demo` | Backup/restore surfaces — all 13 Backup phases at once. `-live` for states the controller actually produced |
| CloudNativePG | `make cnpg-demo` | CNPG renderers/badges. `-live` for real failovers; `-runtime` adds real backups/restore, load, lock chain + Prometheus; fixtures have strict ordering constraints |
| Beyla | `make beyla-demo` | `internal/traffic/beyla.go` — which labels exist depends on Beyla config, not code. Modes `attrs` / `no-network` |
| Cilium | `make cilium-demo` | `internal/traffic/hubble.go` — every Hubble connection lane. Modes `tls` / `netpol` / `install-radar` |
| Kubecost | `make kubecost-demo` | Kubecost 3 current costs — real allocation/assets, local port-forward and in-cluster Service DNS. Modes `query` / `install-radar` / `radar-smoke` |
| Calico | `make calico-demo` | Calico surfaces — both API groups, staged policies, tiers |
| Crossplane | `make crossplane-demo` | Crossplane renderers and spec-shape dispatch |
| Rollouts | `make rollouts-demo` | Argo Rollouts progression. `-roll` advances a rollout |
| GPU ecosystem | `make gpu-ecosystem-demo` | All 37 curated GPU, batch, distributed-training, and inference resource identities. `install-radar` verifies default chart RBAC and group-aware discovery |
| Kueue admission | `make kueue-demo` | Real Kueue reconciliation: admitted/running, quota-blocked with no Pod, and held-queue with no Pod |
| JobSet | `make jobset-demo` | Real JobSet reconciliation: role/index Job-to-Pod lineage, dependency gating, and explicit terminal failure |
| KubeRay | `make kuberay-demo` | Real RayService reconciliation: healthy active Serve revision plus an intentionally failed pending NewCluster revision |
| Workload metrics | `make workload-metrics-demo` | Metrics tab (HTTP rate/errors/latency + CPU/memory/throttling) across Beyla, cAdvisor/KSM and Istio sources. Builds on the Beyla demo; uses its own kubeconfig and the `radar-workload-metrics-demo` context rather than switching yours |

`scripts/rbac-demo.sh` is the odd one out: it seeds RBAC scenarios into the *current* context (no cluster of its own).

**Before calling a UI feature done — consider visual-test.** `make tsc` + `make test` check code; `/visual-test` checks the *screen*. Run it yourself for self-contained UI changes where you can predict what should render; ask the user when the change is broad or the right capture set isn't obvious; skip for pure refactors / Go-only / type-only / doc edits.

### Dev ports
**9280** Go backend · **9273** Vite (proxies `/api` → 9280).

## API Endpoints & CLI Flags

**You MUST read `internal/server/server.go` before adding or modifying any endpoint** — it is the single source of truth for all routes. CLI flags live in `cmd/explorer/main.go`. Key URL patterns — one line per family, plus the gate wherever it differs from the default (a new sibling route should copy the gate, not guess it):
- REST resources: `/api/resources/{kind}`, `/api/resources/{kind}/{ns}/{name}`, `/api/resources/apply` (POST), `/api/resources/preview` (POST, server-dry-run review), `/api/resources/schemas` (POST, connected-cluster OpenAPI schemas)
  - `/api/resources/{kind}` returns `{items, coverage, kind, group, columns, cells}` on every **200**. `coverage` is `{status, scope, narrowedBy?, read, gaps}` (pkg/resourceapi): the scope the answer covers (named namespaces, or what the pin, the caller's access and Radar's collection left), what Radar read, and coded gaps; namespace sets are `{count, names?}`, listing every name up to 64 and otherwise only counting. Failures — GET and preflight denials included — are `{error, error_code, coverage?}` with the status from `readStatus` (`resource_read_errors.go`); a list fails when it has no usable inventory (nothing readable, an oversized result, or a changed connection). `?table=1` populates printer metadata (otherwise columns/cells are null). The UI reads the body by its shape, not `features.resourceReadCoverage` (Hub points one query client at many clusters): older Radar arrays/table envelopes have unknown coverage. Lists reject payloads over `maxItems` (default 25k, summary 50k; maximum 50k) rather than silently truncating. Do not combine table mode with `?include=summary`, which strips fields needed by printer columns.
- SSE streaming: `/api/events/stream`, `/api/traffic/flows/stream`
- WebSocket: `/api/pods/{ns}/{name}/exec`
- MCP: `/mcp` (Streamable HTTP — POST for JSON-RPC, GET for SSE)
- Helm: `/api/helm/releases/...`
- Workloads: `/api/workloads/{kind}/{ns}/{name}/...` (logs, restart, scale, revisions, rollback, images, history). `revisions`/`rollback` accept Deployment, StatefulSet, DaemonSet and **Rollout**, gated by `rollbackableWorkloadKinds` in `server.go`; `images` accepts the same four through a separate map, `workloadImageRoots` in `pkg/k8score/workload_images.go` (a new kind needs both), uses compare-and-swap JSON Patch, and follows a Rollout's `workloadRef`. `history` is the workload's own timeline and never includes sibling workloads — scope rules live in `workload_history.go` and `pkg/timeline`'s `ResourceScope`
- Argo Rollouts: `/api/rollouts/{ns}/{name}/{abort,retry,promote,promote-full,skip-step}` (POST) + `/capabilities` (GET); rollback/history deliberately live on the `/workloads` routes. The status verbs patch the `rollouts/status` subresource, so capabilities SAR `rollouts` **and** `rollouts/status` separately — `patch rollouts` does not imply `patch rollouts/status`. Promotion waits for the controller to observe the current pod template, so `promote-full` can return **503** (`ErrControllerNotCaughtUp`) and is safe to retry; for a `workloadRef` Rollout the caller must be able to `get` the referenced workload. Engine `pkg/rollouts`, handlers `internal/server/rollouts_handlers.go`
- GitOps write evidence: `POST /api/gitops/write-evidence` `{kind, group, namespace, name, paths[], owner?}` reads the target (and its GitOps owner) as the caller and returns, per field path, whether it is in last-applied, which field managers own it and whether an ignore rule covers it, plus the owner's sync policy — never raw managedFields/last-applied. Classification is the pure `evaluateGitOpsWriteGuard` in k8s-ui (`utils/gitops-write-guard.ts`); Set image and Diagnose Apply show it via `GitOpsWriteWarning` + `web/src/hooks/useGitOpsWriteGuard.ts`. Copy never promises a change won't be reverted. See docs/gitops.md
- GitOps controller actions: `/api/argo/applications/...` (sync, refresh, terminate, suspend, resume, rollback, selective-sync), `/api/flux/{kind}/...` (reconcile, suspend, resume, sync-with-source)
- Argo CD API integration: `PUT /api/integrations/argocd` (non-local config only — local mode uses `/api/integrations/connections`; URL/token, probe-before-persist, token preserved across GET-redaction round-trips); `/api/argo/applications/{ns}/{name}/resource-diff` (Git-rendered desired vs live via argocd-server managed-resources; dual RBAC gate + structural Secret redaction; see docs/gitops.md)
- GitOps detail data: `/api/gitops/{tree,insights,destination}/{kind}/{ns}/{name}`. `destination` says where a remote Application or `spec.kubeConfig` Flux object deploys; the object and any kubeconfig Secret are read as the caller, and full server URLs never leave the server
- Nodes: `/api/nodes/{name}/...` (cordon, uncordon, drain (by default waits until the evicted pods are deleted, kubectl parity; observed pods still on the node at the deadline come back in `pendingPods`; failed verification uses `unconfirmedPods` and `verificationError`. `outcome` distinguishes complete/incomplete/unconfirmed/started; expected exclusions do not block completion, `waitForDeletion:false` returns once evictions are accepted), drain-plan (read-only estimate: per-pod evict/skip/may-block with reasons), debug)
- Audit: `/api/audit`, `/api/audit/resource/{kind}/{ns}/{name}`, `/api/settings/audit` (GET/PUT)
- Network trace: `/api/trace/{kind}/{ns}/{name}` (Service/Ingress/HTTPRoute/GRPCRoute/Gateway). `?probe=true` runs DNS/TCP/TLS/HTTP probes — direct in-cluster, via the API server proxy from a laptop — gated by the user's `services/proxy` + `pods/proxy` RBAC
- Capacity (Karpenter): `/api/capacity` (+ `/pools`, `/pools/{name}`, `/pools/{name}/members`, `/demand`, `/activity`) — read-only, gated on the caller's ability to list NodePools, deliberately cluster-wide (no namespace view-filter forwarding). See [docs/capacity.md](docs/capacity.md)
- Upgrade impact: `/api/upgrade-readiness?target={major.minor}` (`?refresh=true` bypasses the scan memo) — cluster-wide (ignores the namespace picker), bounded by the caller's RBAC and the cache scope. Engine `pkg/upgradereadiness`; the service layer in `internal/upgrade` is shared by the HTTP handler and the `get_cluster_upgrade_readiness` MCP tool
- CAPI: `/api/capi/clusters/{ns}/{name}/kubeconfig` (GET), `/api/capi/clusters/{ns}/{name}/connect` (POST)
- Prometheus: the curated chart routes (`/api/prometheus/{resources,namespace,hpa,pvc,rightsizing}/...`) gate (auth-enabled mode) on reading the resource they chart, through the `AuthGate` seam in `internal/prometheus/auth.go`. The unbounded surfaces — `/api/prometheus/cluster`, `/api/prometheus/query`, and the MCP `query_prometheus` / `discover_metrics` / `get_prometheus_rules` tools — gate on an any-namespace `list pods` SubjectAccessReview. The raw query route applies the same response bounding as the MCP tool. No-auth local mode is a passthrough
- Cloud Connect driver lane: `/api/cloud/install/{prepare,start,status,cancel,dismiss}` — the in-product device-flow install. Enabled ONLY local + auth-disabled + no `--cloud-url` (deliberately NOT gated on a loopback listener; a shared listener instead requires an explicit acknowledgement); every other configuration routes to the Hub wizard. The cluster token never serializes through these endpoints

Signals

Stars
3,906
Forks
254
Open issues
45
Contributors
73
Last commit (this folder)
Oct 22, 2026 (6 days ago)
Last release
Oct 22, 2026 (6 days ago)

From GitHub (fetched Oct 24, 2026).

Details

License
Apache-2.0
First seen
Oct 24, 2026
Last checked
Oct 24, 2026

More from skyhook-io

Cite this page

CLAUDE.md · skyhook-io/radar. Agent Mart. https://agentmart.dev/templates/skyhook-io-radar-claude-md (last updated 2026-10-24)