Remote Work Tools

A communication SLA removes ambiguity about response expectations. Remote teams that operate across timezones need written agreements: which channel for what urgency, how long before you can expect a reply, and when escalation is appropriate. This guide provides templates and the tooling to enforce them.

Table of Contents

Core Concepts

A communication SLA defines:

Channel → Purpose → Expected Response Time → Escalation Path

Not all messages deserve the same urgency, and not all channels warrant the same attention. The SLA makes these distinctions explicit and enforced rather than assumed and inconsistent.

Why Teams Need Written Communication SLAs

In co-located offices, communication norms emerge organically. Someone learns that tapping an engineer on the shoulder means “right now,” while leaving a sticky note means “whenever.” Remote teams have no equivalent shared context. A Slack message can feel like either a tap on the shoulder or a sticky note, and different team members read it differently.

Without a written SLA:

The SLA document answers all three scenarios explicitly before they happen.

Channel-by-Channel SLA

# Team Communication SLA

Version: 2.0
Effective: 2026-03-22
Owner: @engineering-leads

---

## Slack

### #incidents
**Purpose:** Active production incidents only
**Response time:** < 5 minutes during business hours
**Response time (off-hours):** Via PagerDuty page only — do not expect Slack monitoring
**Who responds:** On-call engineer + team lead
**Rule:** Tag @on-call for immediate attention; post status updates every 15 minutes

### #deployments
**Purpose:** Deployment notifications (automated + manual)
**Response time:** Informational only — no response required
**Rule:** Automated posts only. For deploy questions, use #engineering

### #engineering
**Purpose:** Technical questions, code review requests, architecture discussion
**Response time:** < 4 hours during business hours
**Rule:** Use threads. Tag specific people if you need a response by EOD.

### #general
**Purpose:** Company-wide announcements, non-urgent team chat
**Response time:** Best effort, same business day
**Rule:** Not a support channel. Announcements get reactions, not replies.

### Direct Messages
**Purpose:** Personal matters, quick questions when you know the person is online
**Response time:** < 2 hours during stated working hours
**Rule:** Check someone's status before messaging. Respect DND settings.
**Escalation:** If no response in 2h, use @mention in relevant channel.

---

## Email

### Distribution lists (team@, eng@)
**Response time:** < 1 business day
**Rule:** Use for external communications, formal requests, and non-urgent cross-team needs.

### Personal email
**Response time:** < 1 business day during working hours
**Rule:** Not for urgent issues. Use Slack for same-day needs.

---

## GitHub / Gitea

### Pull Request Reviews
**Response time:** First review comment within 1 business day of assignment
**Response time:** Blocking review (changes requested) resolved within 4h of author response
**Rule:** PRs unreviewed for > 1 business day get auto-escalated via bot

### Issues
**Response time:** Triage within 2 business days; assignment within 1 week
**Rule:** Issues idle for > 2 weeks get a status comment from assignee

---

## Video Calls

### Scheduled meetings
**Rule:** Join within 3 minutes of start time. After 5 minutes, proceed without.
**Recording:** All recurring team meetings are recorded; links shared in meeting channel within 1h.

### Requested calls
**Response time:** Respond to meeting invite within 4 business hours
**Rule:** Decline with explanation if you can't attend. Don't ghost invites.

Timezone Coverage Matrix

## Active Hours by Time Zone

| Team Member | Timezone | Core Hours (UTC) | Overlap with US-East |
|-------------|----------|------------------|---------------------|
| Alice       | US-East  | 13:00-21:00      | All day              |
| Bob         | US-Pacific| 15:00-23:00     | 3pm-5pm ET           |
| Carlos      | EU-CET   | 08:00-16:00      | 8am-10am ET          |
| Diana       | IST      | 03:30-11:30      | None (async)         |

## Async-First Rules for Cross-TZ Work

1. Write messages that don't require immediate response
2. Include all context in the first message (don't say "hey" and wait)
3. Set explicit deadlines: "Need this by Friday 5pm ET"
4. For Diana's timezone: file issues/PRs before 3pm ET for same-day turnaround

Writing Async-First Messages

The async-first rule is easy to state and hard to practice. Most people write Slack messages the way they’d say something aloud — incomplete, expecting a back-and-forth. That works in an office. For remote teams spanning timezones, every message should be self-contained.

Bad async message:

Hey, do you have a minute? I wanted to ask about the auth service.

Good async message:

Hey @Alice — quick question about the auth service token refresh flow.

Context: I'm building the mobile client and seeing 401s after token expiry.
Looking at the refresh endpoint, I'm not sure whether I should be sending
the refresh token in the Authorization header or the body.

I saw we handle it one way in the web client (body), but the API docs say
header. Which is correct? I can work around this either way — just want to
match whatever the server expects.

No rush — needed by Thursday EOD.

The second message requires no follow-up to answer. Alice can reply with a single sentence when she’s available. That’s what async-first looks like in practice.

Slack Bot Enforcement

Use a bot to track and nudge on SLA violations:

#!/usr/bin/env python3
# scripts/sla-checker.py
# Run as cron to check for unanswered @mentions

import os
from slack_sdk import WebClient
from datetime import datetime, timedelta

client = WebClient(token=os.environ["SLACK_BOT_TOKEN"])

SLA_HOURS = {
    "C_INCIDENTS": 0.083,    # 5 minutes
    "C_ENGINEERING": 4,
    "C_GENERAL": 8,
}

def check_unanswered_mentions():
    for channel_id, max_hours in SLA_HOURS.items():
        try:
            result = client.conversations_history(
                channel=channel_id,
                oldest=str((datetime.now() - timedelta(hours=max_hours*2)).timestamp()),
                limit=50
            )

            for msg in result["messages"]:
                # Skip bot messages and thread replies
                if msg.get("bot_id") or msg.get("thread_ts") != msg.get("ts"):
                    continue

                # Check if message has @mentions with no replies
                if "<@" in msg.get("text", ""):
                    reply_count = msg.get("reply_count", 0)
                    msg_age_hours = (datetime.now().timestamp() - float(msg["ts"])) / 3600

                    if reply_count == 0 and msg_age_hours > max_hours:
                        # Post reminder in thread
                        client.chat_postMessage(
                            channel=channel_id,
                            thread_ts=msg["ts"],
                            text=f":clock1: This message has been waiting {msg_age_hours:.1f}h with no reply. SLA is {max_hours}h."
                        )
        except Exception as e:
            print(f"Error checking {channel_id}: {e}")

if __name__ == "__main__":
    check_unanswered_mentions()
# Add to crontab — run hourly during business hours
0 9-18 * * 1-5 python3 /opt/scripts/sla-checker.py

Calibrating Bot Sensitivity

The bot should nudge, not spam. A few calibration points:

PR Review SLA Bot (GitHub Actions)

# .github/workflows/pr-sla.yml
name: PR Review SLA

on:
  schedule:
    - cron: '0 10,14 * * 1-5'  # 10am and 2pm weekdays

jobs:
  check-pr-sla:
    runs-on: ubuntu-latest
    steps:
      - name: Check stale PRs
        uses: actions/github-script@v7
        with:
          script: |
            const cutoff = new Date(Date.now() - 24 * 60 * 60 * 1000); // 24h ago

            const prs = await github.rest.pulls.list({
              owner: context.repo.owner,
              repo: context.repo.repo,
              state: 'open',
            });

            for (const pr of prs.data) {
              if (new Date(pr.created_at) > cutoff) continue;

              const reviews = await github.rest.pulls.listReviews({
                owner: context.repo.owner,
                repo: context.repo.repo,
                pull_number: pr.number,
              });

              if (reviews.data.length === 0) {
                await github.rest.issues.createComment({
                  owner: context.repo.owner,
                  repo: context.repo.repo,
                  issue_number: pr.number,
                  body: `This PR has been open for >24h with no review. Per our communication SLA, PRs should receive a first review within 1 business day. Reviewers: ${pr.requested_reviewers.map(r => `@${r.login}`).join(', ')}`
                });
              }
            }

Preventing Review Bottlenecks

PR review SLAs fail most often because of unclear assignment. If a PR has no requested reviewers, no one feels responsible. The GitHub Actions workflow above only fires when reviewers are already requested. The companion step is ensuring your PR template prompts for reviewer selection:

## PR Checklist
- [ ] Requested at least one reviewer
- [ ] Linked to relevant issue
- [ ] Added to sprint board
- [ ] Tests passing

Making reviewer assignment a checklist item removes the “I forgot” failure mode.

Onboarding New Team Members

SLA summary card for new hires:

# Communication Quick Reference

**Urgent (production down):** #incidents + PagerDuty
**Need code review:** #engineering + tag reviewer in PR
**Quick question:** DM (check their status first)
**Non-urgent question:** #engineering (expect 4h reply)
**Meeting needed:** Calendar invite + 24h notice
**After hours:** PagerDuty only — never expect Slack

**Do:**
- Always include context and deadline in your message
- Use threads to keep channels readable
- Respect Do Not Disturb hours

**Don't:**
- DM someone just to say "hey, you free?"
- Post the same question in 3 channels
- Expect faster replies by mentioning people repeatedly

The quick reference card should be in your onboarding wiki, your team Notion space, and pinned in the #general channel. New team members who read it in week one set the right expectations immediately. Those who discover it after a frustrating experience are already forming wrong mental models.

Quarterly Review

# SLA Review Checklist (Quarterly)

Review these metrics:
- [ ] Average first response time by channel (export from Slack analytics)
- [ ] PR review SLA compliance (% reviewed within 1 business day)
- [ ] Incidents paged vs Slack-only response time comparison
- [ ] New hire feedback: did SLA set correct expectations?

Update SLA if:
- Team timezone distribution changes
- New channels added
- Recurring SLA violations suggest targets are unrealistic

Reading Slack Analytics for SLA Data

Slack’s built-in analytics (available on Pro and Business+ plans) shows message volume and response times per channel. Export the weekly summary for the channels in your SLA. Look for channels where average response time consistently exceeds the SLA target — that’s a signal to either adjust the target or investigate the cause.

Common causes of consistent SLA violations: