Home

read-only · nothing about your clusters leaves this machine
Read a cluster

Every finding, with the object it rests on.

Reliability, security, cost and topology from get and list. Nothing is installed in the cluster and no object is written.

reading the kubeconfig…
Preflight a change

Find what stops it before you start it.

Which node cannot be drained, what has nowhere to go if a zone fails, what blocks the next upgrade. Free on every plan.

See it first

A full reading of a sample cluster.

A fictional cluster run through the real engine: 141 findings, every panel unlocked, labelled as a sample on every screen.

Recent readings

reading the history…
Kept on this machine, each signed by this install's key. A cluster nobody has read says never read, not zero.

Your plan

checking the licence…
The licence is checked on this machine, against a signature. Nothing is sent anywhere to check it.

Clusters

reading the kubeconfig…
Every context in your kubeconfig. A row says when it was last read and what that reading found; a cluster nobody has read says never read rather than zero.
Prometheus: select one cluster to probe.
select a cluster to begin

Readings

select a cluster
Comparability is decided before you choose. A pair a comparison would refuse says so on its own row, so nobody picks two readings and is turned away afterwards.

Ask before you change

read-only · free on every plan
choose a cluster
It reads only the kinds the question needs, with get and list, and writes nothing. The same question from a terminal: —

Hand the readings to an agent

a corpus, not a keyhole

Every reading this machine has kept can be served over the Model Context Protocol, so an agent works from findings that have already been validated instead of re-deriving them through a cluster connection. The server holds no kubeconfig — there is no client-go in that binary and a test walks its imports to keep it that way — so an agent holding it can read the corpus and cannot touch anything.

Needs a Team licence, and shoalcheck-mcp from the command-line download — the macOS app does not carry it.

claude mcp add shoalcheck -- shoalcheck-mcp
shoalcheck-mcp --cluster prod      # serve one cluster's newest reading
shoalcheck-mcp --print-identity    # say which reading it would serve, then exit
list_readings list_findings explain_finding diff_readings request_reading
run_audit is refused on purpose. An audit lists every kind your read-only role may read, paged — 32 requests on a three-node test cluster, thousands on a large one, and the trace of your own run counts each — and putting that behind a tool call would move the permission off a surface you understand onto one call among twenty inside a model's loop. request_reading hands back the command for you to run instead.

File it in your tracker

text, never a push

Needs a Team licence. It works in this window, from any kept reading.

A finding becomes a ticket from the Queue tab of any reading: title, body, a dedup key, the labels, the engine's own safety verdict, and any compliance term the finding's own text cites — named out loud, because it travels verbatim while the report's control mapping does not.

Nothing is filed. Creating an issue in your workspace needs a credential this window does not hold, and an object in somebody else's tracker is not a read-only tool's to make. You get the text a push would have sent — read it, then paste it.

The dedup key is assay:v1:<cluster>:<finding id>, so filing the same finding twice is something your tracker can refuse rather than something you have to remember. assay is the name this program had when the key was chosen; it stays, so a ticket filed before the name changed is still recognised.

Put it on a pull request

SARIF 2.1.0

GitHub and GitLab code scanning both read SARIF, so a reading can annotate a diff without anything of ours running in your pipeline. The findings arrive as results with their rule, severity and evidence; a cost finding travels without its monthly figure, because SARIF has no field for one.

Needs the command-line download in your pipeline — the macOS app does not carry it — with a Pro licence for the SARIF file and a Team licence for the gate.

shoalcheck audit --context prod --export-sarif shoalcheck.sarif --no-tui   # read, then write the log
# then, in your workflow:
#   uses: github/codeql-action/upload-sarif@v3
#   with: { sarif_file: shoalcheck.sarif }
shoalcheck gate --context prod --baseline baseline.json   # fail the job when something new and high appears

Or write the same file from any kept reading under Handoff in that reading's workspace, here in the window.

The gate exits 0 when the policy is satisfied · 2 when it fired · 1 when the run or the comparison could not be made. Its first run writes the baseline with --update-baseline. A pipeline can act on that without parsing anything.

Take it out as a file

one-way, offline

Needs a Pro licence. It works in this window.

reading the formats…

Written beside the reading, on this machine. Choose a reading under Readings and open Handoff to write one.

Readings on a schedule

Needs a Team licence, and the command-line download on this machine: a schedule runs the shoalcheck command, found beside the app or on your PATH, and the macOS app does not carry it.

no schedules yet
A schedule runs the same read-only audit this window runs, on your machine, and keeps the result with the others. Nothing is uploaded and no reading is sent anywhere.

Updates

—
An update is installed only after its manifest verifies under the Shoalcheck release key, the file's SHA-256 matches the signed one, and the new program starts and names its version. A copy Homebrew or krew installed is left to them.

What this program may do

checking auth plugins…
Read-only by construction: get and list only, and nothing about a cluster leaves this machine. Secret and ConfigMap values, environment variables, container logs and node shells are never read at all.

Diagnostics

a file about this install, not your cluster

There is no telemetry and no crash report: nothing about a run leaves this machine. When a figure looks wrong, this file holds what is needed to reproduce it — and nothing about the cluster it read.

If this window will not start, the command line writes the same file: shoalcheck support, with --input reading.json to describe a reading.

It carries versions, counts, this tool's own rule ids and the cause recorded for any resource kind the run did not get back. No cluster name, no region, no namespace, workload, node, service or hostname, and nothing from any finding — not redacted, absent. It is JSON you can read; there is no support desk, and showing it to anyone is your choice.

This copy

checking the licence…

A key is a signed file naming a plan, an expiry and a cluster allowance. It is checked here, offline, and shared with the command line.

Licence keys are not on sale yet. Every plan reads the same clusters the same way; plans differ in what a reading is kept as and how many clusters one licence covers.

Getting started

  1. Pick a cluster. Every context in your kubeconfig is listed under Clusters. A production context is read the same way as any other: get and list, nothing written.
  2. Ask before a change. Preflight answers one question — drain, zone, upgrade — in seconds, from the kinds that question needs.
  3. Read the whole cluster. A reading names every finding with the object it rests on, what it would cost, and what it could not establish.

Keyboard

When something does not work

the cause, and what fixes it
A cluster is missing from Clusters
The list is every context in your kubeconfig. A context added while the window is open appears the next time it is opened.
It cannot sign in to a cluster
Settings → What this program may do lists the sign-in plugins your kubeconfig names (kubelogin, aws, gcloud…) and whether each was found. Install the missing one where your shell finds it and open the window again: it reads the PATH of your login shell.
A kind reads “refused”
The cluster said no to get or list on that kind for your identity. The reading says so where it matters and the rules that need the kind do not run. A role granting get and list on it is the fix — deploy/rbac.yaml in the command-line download is the role this program needs, and shoalcheck audit --show-permissions lists what an identity can read.
The licence key is rejected
The line under the key says why: not the whole key (paste it again exactly as it arrived), not signed by Shoalcheck, or ended — with its date. shoalcheck licence show says the same from a terminal.
A reading shows only its size, with a key installed
The key is bound to other clusters, or this machine has read as many clusters in 30 days as the plan covers; the result says which. Plan & licence → This copy reads a cluster's fingerprint and says whether the key covers it.
An update does not install
Settings → Updates says why. A folder you cannot write names the download; a copy Homebrew or krew installed updates with their own command.
You need the command line
The macOS app does not carry it. Download shoalcheck_<version>_<os>_<arch> from https://github.com/Shoalcheck/shoalcheck/releases — the same engine. The same page has shoalcheck-mcp and the kubectl plugin.
Where your files are
Readings, history, the licence and these settings: your home folder's .shoalcheck. While the window is open it also serves a copy of each reading from a temporary folder. Nothing about a cluster leaves this machine.

Ask it from the terminal

the same engine, scoped

A question about one change does not need a whole audit. These read only the kinds the question needs and answer with an exit code a script can act on.


          
Exit 0 nothing this model checks stops the change · 2 something does · 1 the answer is partial and the verdict names what was refused.
the reading
Interactive demo · the real window, replaying a session recorded against our kind test cluster with a Team licence; the free download shows each reading's size and its five most serious kinds. Nothing here talks to a cluster. Download the app