| title | Leash - Incident Management & On-Call Escalation | |||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| description | Automated incident management system with on-call rotation, escalation workflows, and multi-channel notifications | |||||||||
| integrations |
|
|||||||||
| categories |
|
|||||||||
| tags |
|
Leash is an automated incident management system that handles incident creation, assignment, escalation, and resolution. It uses Google Sheets as a storage backend for incidents, schedules, and contacts, and delivers notifications through Slack, email (Gmail), and SMS (Twilio).
The entire incident management system is ~200 lines of Python. The hardest part - handling long-running workflows that survive restarts - is straightforward with AutoKitteh:
from autokitteh import next_event, subscribe
# Subscribe to dashboard webhook responses
webhook_subscription = subscribe(
"incident_dashboard_webhook",
filter=f"data.method == 'POST' && data.url.query.unique_id == '{inc.unique_id}'"
)
# Wait for user action with automatic escalation
while inc.state.is_active:
# This wait survives restarts. No external queue or state machine needed.
data = next_event(webhook_subscription, timeout=timedelta(minutes=15))
if data:
# User clicked a button - handle it
inc = handle_action(data.body.form, inc)
else:
# Timeout - escalate to next person
inc = escalate_to_next_assignee(inc)No message queues, no state machines, no orchestration frameworks. The workflow automatically resumes after restarts, preserving all state.
- Durable workflows that can wait hours or days without consuming resources
- Built-in integrations (Slack, Gmail, Twilio, Google Sheets) with no configuration code
- Webhook endpoints with filtering and routing
- Event subscriptions without polling or queue management
- No infrastructure to set up or maintain
- No per-user pricing
- Edit schedules directly in Google Sheets instead of navigating UI forms
- Change escalation logic by editing Python code
- See exactly how it works (check
incidents.py:45) - Own your data and code
- Deploy changes instantly
The system uses 4 AutoKitteh features:
from autokitteh import next_event, subscribe, http_outcome, Event-
Durable Triggers (
autokitteh.yaml): Webhook triggers that create long-running sessionstriggers: - name: new_incident_webhook type: webhook call: handlers.py:on_new_incident_webhook is_durable: true
-
Event Subscriptions (
incidents.py:48): Subscribe to filtered eventswebhook_response_subscription = subscribe( "incident_dashboard_webhook", filter=f"data.method == 'POST' && data.url.query.unique_id == '{inc.unique_id}'" )
-
Durable Waits (
incidents.py:69): Wait for events with timeoutsdata = next_event(webhook_response_subscription, timeout=timedelta(minutes=15))
-
HTTP Responses (
handlers.py:25): Return HTTP responses from workflowshttp_outcome(status_code=201, json={"incident_id": inc.id})
The rest is regular Python business logic.
- Incident Creation: Incidents are created via webhook (POST request with incident details)
- Automatic Assignment: System finds the current on-call person from the schedule stored in Google Sheets
- Notification: Assigned person is notified via all available channels (Slack, email, SMS)
- Interactive Dashboard: Each incident has a unique dashboard URL for taking actions
- Escalation Loop: If no response within configured delay, incident escalates to the next person in rotation
- Resolution: Incidents can be acknowledged, resolved, escalated, or reassigned through the dashboard
- On-Call Rotation: Define schedules with multiple assignees that rotate automatically
- Multi-Channel Notifications: Simultaneously notify via Slack DM, email, and SMS
- Durable Workflows: Incident workflows survive restarts and continue from where they left off
- Interactive Dashboards: Web-based incident dashboards with one-click actions
- Automatic Escalation: Configurable escalation delays with rotation through assignee list
- Google Sheets Backend: All data (incidents, schedules, contacts) stored in Google Sheets for easy management
Leash uses AutoKitteh's durability feature in the new_incident function to ensure incident workflows are reliable and persistent. When an incident is created, the workflow can:
- Survive restarts: If the system restarts during an escalation delay, the workflow resumes exactly where it left off
- Wait indefinitely: Escalation loops can wait for configured delays (minutes, hours, or days) without blocking resources
- Maintain state: All incident context and history is preserved throughout the lifecycle
This means you can confidently deploy updates or handle infrastructure changes without losing track of active incidents or interrupting escalation workflows.
Send a POST request to the new_incident_webhook URL with incident details:
curl -X POST https://api.autokitteh.cloud/webhooks/<WEBHOOK_SLUG> \
-H "Content-Type: text/plain" \
-d "Production database connection timeout - error rate spiking to 15%"The webhook returns the created incident ID:
{ "incident_id": "1" }Configure on-call schedules in the Google Sheets schedule worksheet:
| start_time | end_time | assignees |
|---|---|---|
| 01-01-2025 00:00 | 12-31-2025 23:59 | alice@example.com, bob@... |
- Schedule rows define time periods with lists of assignees
- Assignees rotate automatically on each escalation
- Multiple schedules can overlap (first match wins)
Add contacts in the Google Sheets contacts worksheet:
| name | phone | |
|---|---|---|
| alice@example.com | alice@example.com | +1234567890 |
| bob@example.com | bob@example.com | +1987654321 |
Email and phone are optional, but email at least is recommended. Email is also used to find users in Slack if configured.
Each incident has a unique dashboard URL sent with notifications. Available actions:
- Take: Manually take ownership of the incident (requires authentication)
- Ack: Acknowledge the incident and mark as in-progress
- Resolve: Mark the incident as resolved and close it
- Escalate: Manually escalate to the next person in rotation
- Notify: Re-send notifications to the current assignee
Before deploying Leash, you need to create a Google Spreadsheet with three worksheets:
-
Create a new Google Spreadsheet in your Google Drive
-
Create three worksheets with these exact names:
schedule- Defines on-call schedulescontacts- Contains contact information
-
Set up the
contactsworksheet with these column headers:name | email | phoneThen add your contacts (see "Managing Contacts" section for details)
-
Set up the
scheduleworksheet with these column headers:start_time | end_time | assigneesThen add your schedule rows (see "Managing Schedules" section for details)
-
Copy the Spreadsheet ID from the URL:
https://docs.google.com/spreadsheets/d/SPREADSHEET_ID/editYou'll need this ID for the
GOOGLE_SPREADSHEET_IDconfiguration variable.
Configure the system using project variables in autokitteh.yaml:
GOOGLE_SPREADSHEET_ID: ID of the Google Sheet storing all data (required)ESCALATION_DELAY_MINUTES: Minutes to wait before escalating (default: 15)TZ: Timezone for schedules (default: UTC)FAIL_ON_NO_ASSIGNEE: Whether to fail when no assignee found (default: false)TS_FORMAT: Datetime format for timestamps (default:%m-%d-%Y %H:%M)TWILIO_PHONE_NUMBER: Phone number to send SMS from (if using Twilio)
- gsheets (required): Google Sheets for data storage
- slack (optional): Slack for DM notifications. Ignored if not initialized.
- gmail (optional): Gmail for email notifications. Ignored if not initialized.
- twilio (optional): Twilio for SMS notifications. Ignored if not initialized.
Only the Google Sheets connection is mandatory. All other connections are optional - if not initialized, they will simply not be used for notifications.
- PENDING: Incident created, waiting for assignment
- ASSIGNED: Assigned to someone, waiting for acknowledgment
- IN_PROGRESS: Someone acknowledged and is working on it
- RESOLVED: Incident resolved and closed
- ERROR: Error occurred during processing
Just run make to test locally.
To deploy to AutoKitteh, either hit the "Start With AutoKitteh" button above, or use the CLI:
- Install the CLI https://docs.autokitteh.com/get_started/install
- Authenticate:
ak auth login - Deploy:
make deploy - Login to https://autokitteh.cloud and initialize the connections and variables.