# Add a values.schema.json to a Helm Chart

Yes. An agent writes a JSON Schema for your chart's values.yaml, validates it against every ci values file with helm lint, bumps the version and opens a PR.

[Run this on Rush](https://cloud.getrush.ai/run/add-values-schema/helm/), in a Project that has your repository.

## What the agent does

The agent clones the chart repository into its own cloud sandbox and reads how the repository already handles schemas before it writes one. In prometheus-community/helm-charts, 7 of the 44 charts carry a `values.schema.json`: `alertmanager`, `alertmanager-snmp-notifier`, `prometheus`, `prometheus-ipmi-exporter`, `prometheus-mysql-exporter`, `prometheus-operator-admission-webhook` and `prometheus-sql-exporter`. `charts/alertmanager/values.schema.json` is the house style: draft-07, a top-level `required` list, a `definitions` block for `image` and `resources`, and `additionalProperties: false` on the objects whose keys are fixed. `.github/workflows/ci.yaml` installs the `helm-values-schema-json` plugin and `helm unittest` before `ct lint --config .github/linters/ct.yaml`, and the workflow fails the pull request when more than one chart changed.

For a chart without one, such as `prometheus-blackbox-exporter` at version 11.20.0, the 548-line `values.yaml` is the specification, and the agent reads all of it rather than generating a schema from the defaults alone. The defaults hide the real types: `serviceAccount.name` is empty, so the schema must allow `null` as well as a string; `extraEnv`, `extraVolumes` and `extraSecretMounts` default to `[]` but hold objects; `extraContainers` and `extraInitContainers` are, as the comments say, either a structured array or a templatable string, so each becomes a `oneOf` of array and string; `config.modules` is free-form blackbox configuration and must stay an open object; `kind` is `Deployment` or `DaemonSet`, an `enum`; `hostPort` is an integer with 0 meaning none; `ingress.hosts[].host` passes through `tpl` and stays a string. The agent generates a first draft with the plugin the CI already installs, then edits every one of those by hand and writes a `description` for each top-level key from the comment above it.

The chart's own `ci/` directory is the test corpus: ten values files, from `default-values.yaml` to `daemonset-values.yml`, `networkpolicy-values.yaml` and `service-monitor-tpl-values.yaml`, that CI installs on a kind cluster. Because `helm lint` validates values against `values.schema.json`, the agent runs `helm lint charts/prometheus-blackbox-exporter -f <file>` for each of them and for the bare defaults, and `ct lint --config .github/linters/ct.yaml` as CI does, until every file passes. A file the schema rejects is read before the schema is loosened, because a `ci` file that sets a key the chart ignores is a finding worth a sentence in the pull request.

The repository's rules shape the rest of the diff. `CONTRIBUTING.md` says any change to a chart bumps its `version` by semver, so `Chart.yaml` moves from 11.20.0 by a minor, since a schema can reject values a user passes today; the pull request title starts with `[prometheus-blackbox-exporter] `, which `.github/workflows/pull-request.yaml` enforces; each commit carries a `Signed-off-by` line for the DCO check; and the chart's `README.md` gains a short section, as `charts/prometheus/README.md` has, saying how to regenerate the schema when `values.yaml` changes.

## Start it with one API call

`POST https://api.prix.dev/o/{org}/sessions`

```json
{
  "agent": "claude",
  "input": "Add a values.schema.json to the prometheus-blackbox-exporter chart in this Helm repository. First read charts/alertmanager/values.schema.json for the house style and .github/workflows/ci.yaml and .github/linters/ct.yaml for how lint runs. Read all of charts/prometheus-blackbox-exporter/values.yaml, including comments: generate a draft with the helm-values-schema-json plugin, then fix by hand every key whose default hides its type (nullable serviceAccount.name, lists that default to [], extraContainers and extraInitContainers as array or string, config.modules as an open object, kind as an enum, hostPort as an integer) and add a description per top-level key from its comment. Validate with helm lint -f for the bare defaults and every file under charts/prometheus-blackbox-exporter/ci, then ct lint --config .github/linters/ct.yaml. Bump version in Chart.yaml by a minor, add a README section on regenerating the schema, sign off each commit, and open a pull request titled [prometheus-blackbox-exporter] add values.schema.json that lists any ci values file that needed a schema decision. Change no template.",
  "resources": [
    {
      "url": "https://github.com/your-org/your-app"
    }
  ]
}
```

1. **Get an API key.** In the console, open Settings, then API keys, and create a key for your org. Send it in the Authorization header as a Bearer token.
2. **Send the request.** POST the body in request.json to https://api.prix.dev/o/{org}/sessions, with your repository as the resources URL. The run starts in its own cloud sandbox.
3. **Read what came back.** Follow the run on its live stream or wait for the run.completed webhook, then read the result and its trajectory.

## What comes back

What comes back is a pull request changing three files under `charts/prometheus-blackbox-exporter/`: the new `values.schema.json`, `Chart.yaml` with the minor bump, and `README.md` with the regeneration note. The title starts with the chart's name in brackets, every commit is signed off, and the description lists each `ci` values file with the `helm lint` result and names the keys where the schema makes a choice, such as the array-or-string `extraContainers`.

The pull request's own checks are the repository's: `ct lint` with the schema plugin, the kind-cluster install of each `ci` file in the `integration-tests` matrix, and the title check. A reviewer reads the schema against `values.yaml` for the keys the description flags, and decides whether `additionalProperties: false` on the top level is wanted now or after a deprecation note, since it turns a typo in a user's values into an install failure.

The transcript keeps every `helm lint` run with its output per values file, so a reviewer who doubts that `daemonset-values.yml` passes reads that run rather than repeating it. A follow-up on the same session can loosen one key or add a `unittests/` case once the maintainers answer.

## Run it on every Linear issue labelled agent

In the console, add an automation to the Project with this prompt and a `linear` trigger on `linear.issue.labeled`, filtered to the `agent` label. When a maintainer labels an issue such as "users keep misspelling podSecurityContext, add a schema", the trigger puts the issue after the prompt and the run scopes itself to the chart the issue names, so `ct lint`'s one-chart rule holds; the pull request links back to the issue. Only label changes made by a person in your Rush org fire it.

The same body can be sent from a script with `POST /o/{org}/sessions`, the repository in `resources` and the issue URL beside it, read through your Linear connection. A `request_id` made from the issue id keeps a retried call from opening a second pull request for the same chart.

## Why run it on Rush?

A values schema is a few hundred lines of JSON that must agree with a 548-line `values.yaml` and ten `ci` files, and the only honest check is running `helm lint` against all of them the way CI does. The agent does that in its own sandbox with the same Helm, chart-testing and plugin versions the workflow pins, and keeps the output, so the pull request carries the lint results rather than a claim.

Reading the comments to decide which keys are nullable, which are array-or-string and which must stay open is the part a generator gets wrong and a person finds tedious. The agent does the reading, states each decision in the pull request, and leaves the maintainers one review and one version bump, with the record of every run beside it.

## Frequently asked questions

### Will the schema break existing users' values?

It can, which is why the version bump is a minor and the pull request flags every place the schema is strict. A user who passes a key the chart never read gets an error at install instead of silence. The agent uses `additionalProperties: false` only where `charts/alertmanager` does, on objects with fixed keys, and the reviewer can relax it further before merging.

### Why not just commit the plugin's generated output?

Because the generator reads defaults, and the defaults in this chart are often `[]`, `{}`, an empty string or a comment. `serviceAccount.name` would become a required string, `extraContainers` an array that rejects the documented string form, and `config.modules` a closed object. The draft is the starting point; the hand edits are the work.

### Does it change any template?

No. The prompt rules it out, and the diff is the schema, `Chart.yaml` and `README.md`. If validating the `ci` files reveals a key the templates ignore, the pull request says so as a finding, and a follow-up on the same session can open a separate pull request for the template, since the repository wants one chart per pull request anyway.

### Can it do the other charts without a schema too?

One chart per run. The CI workflow fails when more than one chart changed in a pull request, so the agent scopes itself to the chart the issue names. Start one run per chart, each in its own sandbox, and the pull requests land independently.
