Ansible, Terraform, OpenTofu, Bash, PowerShell, Python, Go

Run everything.
Watch every host.
Prove every change.

SwitchTender is the boundary every change comes through, human operator or AI agent. Nothing runs until it clears one path: request, policy, approval. Then watch every task land on every host, live. Every run leaves behind a cryptographically signed receipt anyone can verify offline against our published key, with no server of ours involved. One binary. Starts in seconds.

Don't take the receipts on faith. Pull the live demo's signed history with curl and check it with the open LoomSeal verifier: Apache-2.0, a published format with conformance vectors, and an independent Python reference, so you are not taking our binary's word for it. Try to refute it →

Already on AWX? switchtender import awx brings your projects, inventories, templates, surveys, and schedules across in one command. Preview the plan, then apply.

Source-available. BSL 1.1. Go SDK with drop-in plugins. One file to back up.

switchtender: fleet health
Fleet health ranking hosts by recent failures, with flaky detection and per-host outcome sparklines

Why SwitchTender? A switchtender is the person who throws the track switches in a rail yard, deciding which train goes where. Nothing moves without them. That's the job here too: one control point for every playbook on every host.

1Requestrecorded before anything acts
2Policysees who's asking, can refuse
3Approvalbinds to the exact change
4Executiongated wherever it runs
5Evidencea receipt verified offline
1binary, zero Kubernetes
<100mscold boot on a laptop
~35MBmemory at idle on Linux
7tools, one engine

Every feature below is free.

All of it ships in the binary you already deployed, no caps, no time limit. Paid tiers only add what never shipped free, and nothing on this page ever moves behind a paywall. If it's on this page, it's in the box.

Provable audit

Every change links into a tamper-evident SHA-256 hash chain; a change that can't be recorded is refused rather than made quietly. Export the chain as a signed LoomSeal bundle and verify it offline with an open, independent verifier, without trusting the server.

What it doesn't claim: the chain proves the record wasn't altered after writing, not that a compromised controller recorded everything. The full boundary statement is in the docs.

Live host-by-task matrix

Read a run like a dashboard instead of a scrollback. Every host and task paints itself live as the run happens, and each cell opens to its own output and exit code.

Multi-tool engine

Ansible, Terraform, OpenTofu, Bash, PowerShell, Python, and Go, each with a dry run. One engine, one UI, one audit trail, on the host or in a pinned container image. Need an eighth? Write it in Go and plug it in.

Balanced splits

Shard a big job across hosts, balanced by each host's measured duration. Retry only the shards that failed, not the whole run.

Fleet memory

It flags flaky hosts, trends how long each task takes, and keeps every host's history across runs. Most controllers forget the moment a run ends.

Visual workflow editor

Drag steps from all seven tools into one graph. Fan out, fan in, retry any step, run the whole pipeline. No YAML by hand.

Schedules you can trust before you save

Type a cron expression and see its next firings before you save it. A scheduled launch carries its template's approvals, notifications, and timeout, and every run records which schedule started it.

Drift detection

A dry run shows exactly what has drifted, across Ansible hosts and Terraform directories, before you touch a thing. One click builds the fix, held for approval. None of the controllers in our comparison document it, and the Terraform control planes that do detect drift do not govern your Ansible fleet beside it.

Enforced approvals

Hold risky runs for sign-off, gated by policy on tool, command, or target. Operators request, admins release. No skipping the gate.

Roles, teams, and orgs

Global roles, teams, organizations, and per-object read, use, and manage grants. Delegate view of one credential without a global viewer, or a whole org inherits a project at once. All of it ships in the core, not a paid tier.

Reach isolated networks

A worker dials out to the control node with a token and opens no inbound port, so it runs jobs inside an air-gapped segment, a DMZ, or a customer network the control node can't reach. One binary, one outbound connection.

Optional advisory AI

Off by default. Switch it on to triage a failure, answer a fleet question, or draft a run from a sentence. It proposes, never executes. Bring your own model: local Ollama, Claude, or any OpenAI-compatible API.

A doctor for your control plane

One click verifies every registered reference: templates to inventories, projects, and credentials, schedules to templates, every cron expression. Broken links surface with a fix button before they break a run.

Run it again, your way

Rerun any finished run with its exact spec, credentials included, one click. Or launch a template with overrides: host limit, inventory, credential picks, extra vars, dry run. Every override is authorized like a fresh launch.

Built for audits and sharing

Every list exports to CSV or JSON, filtered exactly as you see it. Every run exports its events, log, and per-host results. Copy a link to any run, in any of the three themes.

Every run knows where it came from

Each run records what fired it, the template, schedule, rerun, or drift fix behind it, and who asked. Add labels like env=prod, then search with fielded terms: status:failed host:web01 label:env=prod, resolved across your whole history.

Notifications everywhere

A finished run reaches Slack, Teams, Discord, Mattermost, Rocket.Chat, ntfy, email, or a webhook; a failure pages PagerDuty, alerts Grafana OnCall, or texts through Twilio. Eleven channels, server-wide or per template, so each team pages its own people.

Secrets kept out of the log

Sealed at rest, sourced live from Vault, AWS, Google, Azure, CyberArk, or 1Password, and kept off the command line so nothing shows in the process table. A tool that prints a secret shows ***. Typed cloud credentials inject the exact variables each tool expects.

What it doesn't claim: log masking matches the secret's literal text, so a value a tool re-encodes as base64 or hex, or one shorter than four characters, is not caught. Every tool in the field has the same limit; treat it as a safety net, not a boundary.

See it in action

A run painted live as a host-by-task matrix, not a wall of scrollback. The colors speak Ansible: green means ok, amber means the task changed the host, red means failed, gray means skipped.

switchtender: run

Design pipelines by dragging, not by YAML

Wire Ansible, Terraform, OpenTofu, Bash, PowerShell, Python, and Go steps into a graph, plus any tool you plug in. Fan out, fan in, and run the whole thing as one pipeline with per-step retries. It runs in the same binary as everything else.

switchtender: workflow editor
Above execution

Governance the rest
of the field skips

Multi-tool execution is common now. The difference sits above execution: a control plane that proves what happened and enforces what's allowed.

  • Tamper-evident, signed audit. Alter one entry and the chain breaks. Prove the trail is intact, offline.
  • Change control by policy. A prod terraform destroy holds for an admin's sign-off, automatically.
  • Secrets masked, sourced, sealed. They never land in a log and never live in SwitchTender if you don't want them to.

Evidence you can hand to an auditor.

Most controllers keep an activity log: rows in their own database, editable by whoever holds the database. SwitchTender writes every change into a hash chain, then gives you six ways to carry the proof out of the building. What changed, who asked, and who approved it become things you show, not things you say. Every claim on this page is defended adversary by adversary, limits included, in the threat model.

A receipt for every change

Every mutation through the API returns an Audit-Receipt header naming its place in the chain. Keep it. Months later, switchtender audit receipt proves the chain still holds that entry at that position, and a server that dropped it can't answer.

A dossier for every run

The Evidence button on any run, or switchtender audit run, emits one self-contained file: the spec, the risk grade, who approved it, what happened on each host, and the receipts and anchors behind all of it. An auditor's sample request is answered in one export.

The change register

switchtender audit report renders every change in a period, the sample a SOC 2 CC8.1 or ISO/IEC 27001 A.8.32 review asks for; the control mapping and a sample pack show exactly what an assessor gets. Point --evidence-dir at an archive and registers write themselves on a cadence, so the evidence exists before anyone asks.

A witness on another machine

switchtender witness watches the chain's public feed from a second machine, keeps a signed checkpoint of what it saw, and raises a finding when history shrinks or a beat goes missing. The hosted witness answers with countersigned attestations that verify offline against a key you pinned.

Receipts in your SIEM

Stream every audit entry into your SIEM as NDJSON or RFC 5424 syslog, each event carrying its chain receipt. Delivery is at-least-once behind a durable cursor, so an outage delays events instead of dropping them, and any sampled event redeems against the live chain.

Verified without trusting the server

Export the chain as a signed LoomSeal bundle and verify it on a machine with no network, using an open verifier that isn't SwitchTender. Or drop it into your browser and watch the same verifier check it, offline, with nothing uploaded. A checker anchors the signing key without taking the server's word for it: each install publishes its key at /.well-known/loomseal.json, you can pin a fingerprint handed over out of band, and the hosted witness countersigns it, so the key's authenticity is checked independently, not asserted by the same box. The binary proves itself the same way: switchtender version --verify hashes the running build against the BINARY_SHA256SUMS published with its GitHub release.

Don't take our word for it. Check the live demo's chain right now.

These run against demo.switchtender.com, a live instance that wipes and reseeds its history every night. That makes the third command a live-fire exercise: become its witness today, run it again tomorrow, and the witness will refuse the rebuilt history with a finding. That alarm is the product working. A nightly reseed is exactly what a rewritten chain looks like from outside, and nothing the server says can talk your witness out of what it saw.

# 1. the server re-verifies its whole chain, entry by entry
curl -s https://demo.switchtender.com/v1/audit/verify

# 2. pull the whole chain as a signed bundle, yours to keep and verify anywhere
curl -s https://demo.switchtender.com/v1/audit/bundle > demo-bundle.json

# 3. become its witness: keep a signed checkpoint of the head you saw.
#    Run it again after tonight's reseed and watch it catch the rewrite.
switchtender witness --server https://demo.switchtender.com --once
AI agent change governance

Agents are principals here, not API keys.

An agent's token is minted as an agent's, naming the human it acts for, and capped below admin so it can never approve its own work or touch identity, access, or secrets. Policy can say what an agent may do, what needs a person first, and what it may never do at all. Every change lands in the chain as the agent's, on behalf of its human, and the receipt proves a person approved exactly the change that ran. The gate is the agent's only door. We don't build the best AI agent. We govern what agents are allowed to do.

Optional layer, off by default

None of this needs AI.
Turn it on if you want it.

Everything above runs with no model anywhere near it: the live matrix, the balanced splits, the governance, the audit chain. Advisory AI is an add-on, and nothing else depends on it.

Switch it on and it proposes a diagnosis for a failed run, answers a plain-English question about your fleet, or drafts a run from a single sentence. That's all it does. It can't execute anything. Every draft waits at the same approval gate you do, and it never sits in the execution path. Bring your own model: Ollama on your hardware, Claude with your Anthropic key, or any OpenAI-compatible endpoint. Secrets are masked before a model sees a byte.

switchtender: AI triage
A failed run with the AI triage panel isolating db01's apply step as the root cause and suggesting next steps
switchtender: ask your fleet
The overview page answering a plain-language question about which hosts are failing and where to start

AI advises. SwitchTender enforces.

Extensibility: SDK + drop-in plugins

Seven tools in the box.
Add more in Go.

Ansible, Terraform, OpenTofu, Bash, PowerShell, Python, and Go all run out of the box, no plugins required. When you need an eighth tool, a custom secret backend, a new AI provider, or your own notification channel, you write it in Go against a stable SDK. Compile it into the binary, or build it once and drop it into --plugins-dir, where a stock release loads it at startup over gRPC with mutual TLS and treats it as its own. A plugged-in tool submits, validates, and audits like a built-in. A plugged-in channel gets every terminal run with secret-carrying vars already redacted. The SDK guide walks both paths and carries a complete extension you can build and drop in.

// build once, drop into --plugins-dir, no recompile of switchtender
import "github.com/kordloom/switchtender/sdk/plugin"

func main() {
	plugin.Serve(&plugin.Extension{
		Tools:     map[string]sdk.ToolRunner{"packer": sdk.ToolRunnerFunc(runPacker)},
		Notifiers: map[string]sdk.Notifier{"pagerduty": sdk.NotifierFunc(page)},
	})
}

The honest side-by-side

How SwitchTender measures up against the tools teams actually shortlist. Where it's still young, the comparison doc says so plainly. Go deeper on any one: AWX, Ansible Automation Platform, Ascender, and Semaphore. How runs execute under load covers the engine underneath.

CapabilitySwitchTenderAWXAAP / TowerSemaphoreRundeck
Deploy without KubernetesVM installer
Live host-by-task matrixper-host summaryper-host summaryper-node, per-step
Ansible, Terraform, OpenTofu, Bash, PowerShell, Python, GoAnsible onlyAnsible onlyno Go, no uniform dry runscripts, no native IaC
Duration-balanced job splittinground-robinround-robin
Fleet memory: flaky hosts, trends
Tamper-evident, signed auditactivity logactivity log
Secret values auto-masked in logsopt-inopt-insecure options
Enforced approval policiesbasicbasicenterprise
One-command migration in
Drift detection from a dry run
Drag-and-drop workflow editorlinear steps
Advisory AI, read-only: triage, answers, drafts, never executesauthoring assist
Drop-in Go plugins: tools, secrets, AI, notifiersJava plugins
Container execution for every toolAnsible onlyAnsible only
Typed cloud credentials, pluggable typestyped, not pluggabletyped, not pluggable
Organizations, teams, per-object grantsteams, four fixed rolespolicy files, no GUI editor
Instance groups: pin work to worker poolsenterprise
Active-active HA on PostgreSQLvia Kubernetesvia Kubernetesenterprise

Checked against each vendor's own documentation on 10 August 2026: AWX 24.6.1, Ansible Automation Platform 2.7, Semaphore 2.19.7, Ascender 25.4.0, and Rundeck 6.0.1. All five of these products keep shipping, so a table like this starts going stale the day it's written. If a row is wrong, open an issue and we'll fix it.

Bring the whole thing
with you.

A migration is one command, not a rebuild. AWX, Semaphore, Rundeck, and Jenkins each have an importer, and Ansible Automation Platform, Tower, and Ascender export through the same awxkit command with the same top-level keys, so the AWX importer reads them too. Even a crontab imports, line by line, into governed schedules. Export, preview exactly what will land, then apply. Projects, inventories with their hosts and groups, dynamic inventory sources, job templates, surveys, schedules, and credential shells all come across in one pass. A malformed asset is skipped with a warning instead of failing the import, so even a partial export migrates everything it can.

# 1. preview: read the AWX export, print the plan, write nothing
switchtender import awx awx-export.json --db switchtender.db

# 2. apply: create every project, inventory, template, survey, and schedule
switchtender import awx awx-export.json --db switchtender.db --apply

# on Semaphore instead? swap one word:
switchtender import semaphore export.json --db switchtender.db --apply

Credentials arrive as named shells, since these exports omit secret material by design. Re-enter each secret once and every template that references it works. The switching guide maps every AWX concept to its SwitchTender equivalent, and the AWX alternative page makes the full case.

Running in seconds

One binary, one SQLite file. No control plane to stand up first.

# install (or grab a release binary)
go install github.com/kordloom/switchtender@latest

# serve: SQLite by default, PostgreSQL optional
switchtender serve --addr :8080 --db switchtender.db

# open the UI
open http://localhost:8080/ui/

Three looks. Pick your line.

The whole UI ships with three themes. Loom is the signature look, Linen is stark white, Ink is warm black. Switch in one click from the sidebar, or link any page with ?theme=.

Every theme keeps the same status colors, so a failed host reads the same in all three.

Every run leaves a receipt.

Who asked, who approved, what changed on every host, and proof that none of it was edited after the fact. Human or AI agent, the record is the same, and anyone can check it offline without trusting your server or ours.

Self-hosted, nothing phones home, and a lapsed license takes nothing with it. You never bet your operations on our survival.