Salt × AI · differential edge
AI writes plausible Salt YAML. Sometimes it runs. The patterns we use, and the failure modes worth knowing.
v1.0 · Updated 2026-05-09
Most "AI for Salt" content reads like a sales deck. In practice it's good at four specific things and unreliable at four others.
-l debug output..sls files.The pattern: AI drafts, you read every line, then you run on a test minion before production. Treat it like a junior.
Whether AI-generated YAML runs first try or wastes your afternoon comes down to the prompt.
Salt minion version: 3006.4
Target OS: Ubuntu 22.04
Goal: install nginx, enable+start the service, allow ports 80/443 in ufw
Generate a Salt state file (.sls) using these modules only:
- pkg.installed
- service.running
- cmd.run
Include explicit `require:` chains so order is unambiguous.
No comments. YAML only.
Why it works: it pins the version (no 2019-era patterns), names the OS (right package names), constrains the modules, and makes ordering explicit.
Set up a webserver with Salt
Why it fails: No version → mixed-era YAML. No OS → wrong package names. No module constraint → AI picks weird modules. No require: instruction → implicit ordering.
For complex states, ask AI for the smallest possible working version first. Get it to apply cleanly on one test minion. Then ask it to expand: firewall rules, TLS, monitoring. Each iteration stays small enough that you can read every line.
Always pin the version. Salt's release cadence means modules and signatures shift. AI trained on Salt 3001 docs will hand you patterns that 3006+ rejects. One line at the top — Salt minion version: 3006.x — saves you hours of debugging deprecated syntax.
When a state fails, AI is faster than -l debug for the first read. For the actual fix, less so.
Run with -l debug. Copy the entire output, not just the red bit. AI uses the surrounding context.
Salt version, target OS, the failing state file, the full traceback.
"What's wrong, and what's the minimum change?" Asking for the minimum forces a focused diagnosis instead of a rewrite.
service.runing vs service.running — humans miss it, AI catches it.{{ }} inside a quoted string is tedious to spot by eye.If the failure is a multi-minion race, a state that only fails under load, or a config quirk in your GPG/PKI setup, AI can't see your environment. A senior with shell access wins.
MCP is Anthropic's protocol for letting Claude call real tools in your environment. No official Salt MCP server exists. There should be. The architecture we use:
test.ping, grains.items, state.show_sls, cp.list_statesstate.apply, cmd.run) defaults to test=True and requires explicit confirmationWithout MCP, Claude generates Salt blindly. It can't see installed packages, your existing states, or grain values. With read-only MCP wired up, Claude can ask ("what version is minion-foo running?", "what's in your existing nginx state?") and write states that fit your environment.
Never expose cmd.run as an unconstrained tool. An LLM with arbitrary shell access is a vulnerability waiting to happen. Default everything to read-only, gate mutating calls behind explicit approval, and log every call.
Pillar generation is where AI saves the most time. Repetitive structure, predictable shape, low risk if you read the diff.
The secret-sanitizing trick: before pasting any pillar to AI, search-and-replace your real values with <PLACEHOLDER> tokens. Get the AI's output back. Re-substitute the real values locally.
AI-generated Salt that compiles plausibly but doesn't run is the biggest time-sink. Five real examples, with the quick checks that catch them.
AI invents modules that sound right but don't exist.
ensure_running:
systemd.unit_running: # NOT A REAL MODULE
- name: nginx
service.running, not systemd.unit_running. Verify against the state module index before applying.AI generates require: blocks that reference state IDs that don't exist or are misspelled. Salt fails the compile step with a confusing error.
salt-call --local state.show_sls your.state first. It compiles without applying. Compile errors surface in seconds.AI trained on 2019 docs will suggest module signatures that worked then but were removed in 3006+. Especially common with pkg.installed arguments and old file.managed options.
Salt minion version: 3006.x at the top of every prompt cuts this in half.AI references grains inside pillar files (which render before grains are available), or pillar values inside states without remembering the lookup syntax. Looks fine, fails at compile.
AI states something authoritatively that's just wrong. "Salt automatically retries failed states" — it doesn't, unless you wire it up. "onchanges is the same as watch" — they're different.
# 1. Compile-only — catches typos, missing modules, bad requires
salt-call --local state.show_sls your.state
# 2. Dry-run — catches everything else, no changes made
salt 'minion-test' state.apply your.state test=True
# 3. Read the diff. Then apply for real.
salt 'minion-test' state.apply your.state
Saltify engagements include the AI tooling your team needs to keep using Salt without us in the room.
AI doesn't replace anyone, but it usually makes seniors faster and juniors functional. Routine state work moves in-house; we get called back for the architectural decisions, the blue/green cutovers, and the things that need real judgment.
Want this for your team? AI uplift is bundled with every Saltify engagement — blue/green build-outs, multi-master deployments, VCF Salt installs. We don't charge extra for the prompt library, MCP server, or runbook templates. Talk to us.
Built from production Saltify engagements + Anthropic's MCP spec. Patterns evolve as Salt and Claude both ship — last reviewed May 2026.