Skip to main content
By the end of this guide, you’ll have maintenance windows configured for the three flows that actually happen in production:
  1. A planned deploy or migration that takes 30 minutes — schedule a one-shot window from your deploy script.
  2. Recurring weekly infrastructure maintenance — a single window with an iCal RRULE.
  3. An AI agent scheduling the window for you — via the MCP server’s create_maintenance_window tool.
For the conceptual model and the field reference, see Maintenance windows.
  • DevHelm CLI installed (or any SDK / MCP-enabled agent)
  • An API token (DEVHELM_API_TOKEN) and the org / workspace headers set
  • At least one monitor running — see the quickstart
Maintenance windows are state, not infrastructure. They live in the imperative surfaces (CLI, SDKs, MCP, REST API, dashboard) — not in devhelm.yml or the Terraform provider. See Why not Terraform / not in devhelm.yml? for the rationale.

Schedule a 30-minute window now

Pick the surface you’ll wire into your deploy pipeline.
devhelm maintenance-windows create \
  --start "2026-05-15T14:00:00Z" \
  --end   "2026-05-15T14:30:00Z" \
  --reason "Quarterly DB upgrade" \
  --monitor <monitor-id>
from devhelm import Devhelm

client = Devhelm()  # picks up DEVHELM_API_TOKEN + tenant headers from env

window = client.maintenance_windows.create({
    "monitorId": "<monitor-id>",
    "startsAt":  "2026-05-15T14:00:00Z",
    "endsAt":    "2026-05-15T14:30:00Z",
    "reason":    "Quarterly DB upgrade",
})
print(f"window opened: {window.id}")
import {Devhelm} from '@devhelm/sdk'

const client = new Devhelm({token: process.env.DEVHELM_API_TOKEN!})

const window = await client.maintenanceWindows.create({
  monitorId: '<monitor-id>',
  startsAt:  '2026-05-15T14:00:00Z',
  endsAt:    '2026-05-15T14:30:00Z',
  reason:    'Quarterly DB upgrade',
})
console.log(`window opened: ${window.id}`)
curl -X POST https://api.devhelm.io/api/v1/maintenance-windows \
  -H "Authorization: Bearer $DEVHELM_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "monitorId": "<monitor-id>",
    "startsAt": "2026-05-15T14:00:00Z",
    "endsAt": "2026-05-15T14:30:00Z",
    "reason": "Quarterly DB upgrade"
  }'
Omit monitorId (or --monitor) for an org-wide window covering every monitor — the right call when a deploy or upgrade touches the whole platform. To cover a specific list of monitors (the API stores one monitor per window), pass several IDs to the CLI’s --monitor flag and the CLI fans out into one window per monitor:
devhelm maintenance-windows create \
  --start "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
  --end   "$(date -u -d '+30 minutes' +%Y-%m-%dT%H:%M:%SZ)" \
  --reason "Production deploy $(git rev-parse --short HEAD)" \
  --monitor 9f4a-...,8b21-...,7c33-...
The SDKs are deliberately one-window-at-a-time so the call site stays explicit; loop over your list there.

Wire it into your deploy script

The full pattern is create → run → cancel. If the deploy succeeds in 5 minutes, cancel the window early; if it runs long, extend (don’t replace) the window.
set -euo pipefail

WINDOW=$(devhelm maintenance-windows create \
  --start "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
  --end   "$(date -u -d '+30 minutes' +%Y-%m-%dT%H:%M:%SZ)" \
  --reason "Deploy $(git rev-parse --short HEAD)" \
  --monitor "$MONITOR_ID" \
  -o json | jq -r '.id')

trap 'devhelm maintenance-windows delete "$WINDOW" || true' EXIT

# ... run your deploy ...
The trap … EXIT line guarantees the window is cancelled even if the deploy script aborts — a half-suppressed monitor outliving the deploy is the failure mode you want to avoid.

Extend instead of letting it expire

If a migration runs long, update the existing window with a new --end rather than waiting for it to expire and then scheduling a new one. The expiry / re-create path leaks alerts during the gap.
devhelm maintenance-windows update "$WINDOW" \
  --start "$ORIGINAL_START" \
  --end   "$(date -u -d '+30 minutes' +%Y-%m-%dT%H:%M:%SZ)" \
  --reason "Migration still running"
The update endpoint is a full replacement (PUT) — pass --start and --end together.

Schedule a recurring window

For weekly maintenance, use an iCal RRULE. The first start/end define the first occurrence; the RRULE generates the rest.
devhelm maintenance-windows create \
  --start "2026-05-19T02:00:00Z" \
  --end   "2026-05-19T04:00:00Z" \
  --repeat-rule "FREQ=WEEKLY;BYDAY=TU" \
  --reason "Weekly infra maintenance"
client.maintenance_windows.create({
    "startsAt":   "2026-05-19T02:00:00Z",
    "endsAt":     "2026-05-19T04:00:00Z",
    "repeatRule": "FREQ=WEEKLY;BYDAY=TU",
    "reason":     "Weekly infra maintenance",
})
await client.maintenanceWindows.create({
  startsAt:   '2026-05-19T02:00:00Z',
  endsAt:     '2026-05-19T04:00:00Z',
  repeatRule: 'FREQ=WEEKLY;BYDAY=TU',
  reason:     'Weekly infra maintenance',
})
Common RRULE patterns:
ScheduleRRULE
Every TuesdayFREQ=WEEKLY;BYDAY=TU
First day of each monthFREQ=MONTHLY;BYMONTHDAY=1
Every other SaturdayFREQ=WEEKLY;BYDAY=SA;INTERVAL=2

Let an AI agent schedule it for you

If you’re driving a deploy from Cursor, Claude Desktop, or any other MCP-enabled assistant, the DevHelm MCP server exposes maintenance-window tools that an agent can call before the deploy and again after it finishes:
  • create_maintenance_window — open the window scoped to the affected monitors.
  • update_maintenance_window — extend if the deploy runs long.
  • cancel_maintenance_window — close it once the deploy verifies green.
  • list_maintenance_windows — check whether one is already open before scheduling.
  • get_maintenance_window — fetch a single window by ID.
A typical agent flow looks like:
Agent: I’m about to run the production migration. I’ll open a 30-minute maintenance window first so on-call doesn’t get paged. (calls create_maintenance_window with monitorId, startsAt, endsAt, reason: "Postgres major upgrade — DB-1234") Agent: Window scheduled. Running the migration. (deploy runs) Agent: Migration succeeded, all health checks green. Closing the window so alerting resumes. (calls cancel_maintenance_window with the window ID)
Wire this into your agent’s pre-deploy / post-deploy hooks so it’s the default path, not something a human has to remember. See DevHelm Skill for the agent-side instructions.

What happens during a window

BehaviorDuring an active window
Monitor checksStill run. Maintenance windows do not pause monitoring.
Check resultsStill recorded. Your historical uptime / response-time charts stay accurate.
IncidentsStill created — but at severity MAINTENANCE instead of DOWN / DEGRADED.
Notification policiesSkipped when suppressAlerts is true (the default).
Channel deliveries (Slack / PagerDuty / email / …)Suppressed.
Resume after the window endsImmediate — the next failed check evaluates policies normally.
For the full precedence story (maintenance windows vs. resource-group suppression vs. notification policies), see Alert suppression.

Listing and inspecting windows

Use the listing flags to confirm what’s currently open before scheduling:
devhelm maintenance-windows list --status active
devhelm maintenance-windows list --status upcoming
devhelm maintenance-windows list --monitor <monitor-id>
active returns currently open windows; upcoming returns scheduled-but-not-yet-open windows. Past / cancelled windows are not surfaced in the list today — check the audit log if you need that history.

Next steps

CLI command reference

Full flag list and deploy-script pattern.

MCP server overview

Wire AI agents into your deploy flow.

Alert suppression

Maintenance windows vs. resource-group suppression.

CI/CD pipeline

Add maintenance windows to your release workflow.