Nightly config drift check against approved versions with Claude Code and rConfig MCP
rConfig tells you what changed between two backups. A different question matters for standards-driven networks: is each device still on the configuration we last signed off? Small changes add up, and a device can be ten changes away from its approved state without any single change looking significant. This playbook keeps one approved version per device in Git, and each night an agent compares the latest backup with it and reports only the devices that have moved.
Best for: core and WAN devices under change control, regulated estates, teams with a sign-off step for config standards.
Tools: rConfig, Claude Code (claude -p), cron on a server inside your network, a Git repository, a chat webhook.
rConfig tools used: get_devices, get_config_history, get_config_diff.
rConfig docsNetwork Configuration Diff Analysis - rConfig V8Network configuration change analysis with rConfig V8 diff tools: track, compare, and analyze device changes for change management and auditing.Read the docs
How it flows
flowchart LR
C["cron 02:15"] --> S["drift-check.sh"]
G[("approved.json<br/>in Git")] --> S
S --> A["claude -p"]
A -- "get_config_history<br/>per device" --> R["rConfig MCP"]
A -- "get_config_diff<br/>approved → latest" --> R
A --> J["report.json"]
J --> D{"status"}
D -- "clean" --> N["Nothing posted"]
D -- "drift" --> P["Chat post with<br/>one line per device"]
D -- "error" --> E["Alert: check failed"]
The baseline file
One entry per device: the rConfig config version ID a person approved, and who approved it. Get the first IDs by asking an agent once, interactively, for the latest running-config version of each device in scope, and review them before committing.
{ "scope": { "groups": ["Core", "WAN"] }, "devices": { "dub-core-01": { "version": 18342, "approved_by": "a.okafor", "approved_on": "2026-10-28" }, "dub-core-02": { "version": 18351, "approved_by": "a.okafor", "approved_on": "2026-10-28" }, "lon-wan-01": { "version": 17990, "approved_by": "s.nolan", "approved_on": "2026-10-14" } }}Approving drift is a pull request that changes a device’s version to the new one. The reviewer reads the drift report, the diff in rConfig, and the change ticket before merging.
The job
#!/usr/bin/env bashset -euo pipefailcd /opt/netops/drift-baseline && git pull --quiet# RCONFIG_MCP_TOKEN and CHAT_WEBHOOK_URL come from /etc/netops/drift.env (mode 0600).
PROMPT=$(cat <<EOFYou are checking network devices for drift from their approved configuration,using rConfig's tools only. The approved baseline is:
$(cat approved.json)
For each device in "devices":1. Find its latest running-config version with get_config_history, filtered to the running-config command.2. If the latest version ID equals the approved version, it is clean.3. Otherwise call get_config_diff from the approved version to the latest. Summarise the change in one sentence and rate it low, medium or high: high for ACL, AAA, SNMP, routing or management-access changes.Also list devices in the scope groups (get_devices) that are missing from thebaseline, and devices whose newest backup is older than 36 hours.
Output only this JSON, no prose:{"status": "clean" | "drift", "checked": <n>, "drift": [{"device", "approved_version", "latest_version", "latest_at", "risk", "summary"}], "not_in_baseline": [<device names>], "stale": [{"device", "latest_at"}]}If rConfig's tools are unavailable or any call fails, output{"status": "error", "detail": "<what failed>"} and stop.EOF)
claude -p "$PROMPT" --allowedTools "mcp__rconfig__*" --output-format json \ | jq -r '.result' > report.json
status=$(jq -r '.status' report.json)case "$status" in clean) exit 0 ;; drift) text=$(jq -r '"Drift from approved configs (" + (.drift|length|tostring) + " of " + (.checked|tostring) + " devices)\n" + ([.drift[] | "• [\(.risk)] \(.device): \(.summary) (v\(.approved_version) → v\(.latest_version))"] | join("\n"))' report.json) curl -fsS -X POST -H 'Content-Type: application/json' \ -d "$(jq -n --arg t "$text" '{text: $t}')" "$CHAT_WEBHOOK_URL" ;; *) curl -fsS -X POST -H 'Content-Type: application/json' \ -d '{"text":"Nightly drift check FAILED: see report.json on the runner"}' "$CHAT_WEBHOOK_URL" exit 1 ;;esac15 2 * * * netops set -a; . /etc/netops/drift.env; /opt/netops/drift-check.sh >> /var/log/netops/drift.log 2>&1The project folder holds the .mcp.json from the Claude Code guide, which reads the token from RCONFIG_MCP_TOKEN. Run the job at least an hour after rConfig’s nightly backups finish, so it compares tonight’s configs.
An illustrative post:
Drift from approved configs (2 of 14 devices)• [high] dub-core-02: SNMP community added with no ACL (v18351 → v18877)• [low] lon-wan-01: interface description changed on Gi0/0/2 (v17990 → v18802)Limits to know
- History is read per device. Fourteen devices is fourteen history calls and up to fourteen diffs. Keep the baseline to the devices you actually sign off, and split large estates into several baseline files and jobs.
- Noise hides real drift. Lines that change on every backup (timestamps, counters) make every device look drifted. Remove them at source with diff exclusions.
- The risk rating is the model’s. It’s a triage hint for the reviewer, not an assessment. The diff in rConfig is the evidence.
- Version history must reach back. If rConfig’s retention has removed the approved version, the diff fails. The prompt reports that as an error, and the fix is to approve a newer version.
Guardrails
- The job reads rConfig and posts to one webhook. It has no Git write access: approvals happen in pull requests, by people.
- The token belongs to a service user whose role covers only the baseline’s groups.
- A failed run posts a failure message. Silence only ever means “checked and clean”.
Variations
- Open an issue instead of posting. Replace the chat post with
gh issue create, one issue per drifted device, labelled by risk. - Per-team baselines. One baseline file per team or customer, each with its own token scoped to that team’s devices.
- Weekly roll-up. Keep each night’s
report.jsonas a dated file and ask an agent on Fridays which devices drifted most often.
Related reference
- Network configuration diff analysis
- Diff exclusions
- Connect an AI agent over MCP
- Scheduled Tasks
- Claude Code
Frequently asked questions
How is this different from rConfig's own change detection?
rConfig records every change between two backups. This playbook compares each device with a version a person approved, which may be many backups ago, so drift that built up over several small changes still shows as one item until someone approves it.
Where is the approved baseline kept?
In a JSON file in a Git repository: one rConfig config version ID per device. Approving drift is a pull request that updates the ID, so every approval has an author, a reviewer and a date.
Why does the script decide whether to post, not the agent?
The agent returns JSON with a fixed status field. A deterministic script reads it and decides what to send, so a quiet night never produces a message and an agent error never looks like a clean night.