Webhooks & Events

godotz.ai emits structured events at every meaningful state transition: task lifecycle, agent status, budget alerts, and fleet health changes. Events are delivered via ntfy (push notifications) and optionally forwarded to HTTP webhooks.


ntfy Integration

godotz.ai uses ntfy as its primary notification transport. ntfy is self-hostable and has native mobile/desktop clients.

Configuration

# ~/.config/omp/config.yml (notifications section)
notifications:
  ntfy:
    enabled: true
    server: https://ntfy.sh         # Or your self-hosted instance
    topic: omp-fleet-<your-token>   # Unique topic per fleet
    priority: default               # min | low | default | high | urgent
    token: ""                       # ntfy access token (if server requires auth)

Subscribe to events

# Terminal (curl stream)
curl -s https://ntfy.sh/omp-fleet-abc123/json

# ntfy CLI
ntfy subscribe omp-fleet-abc123

Fleet Events

Event Taxonomy

EventSourceSeverity
agent.startedgodotz.ai agentinfo
agent.stoppedgodotz.ai agentinfo
agent.crashedgodotz.ai agenthigh
task.createdbeadsinfo
task.donebeadsinfo
task.blockedbeadswarn
epic.closedbeadsinfo
budget.alertLiteLLMwarn
budget.exceededLiteLLMurgent
model.degradedLiteLLM healthwarn
model.unavailableLiteLLM healthurgent
node.offlinefleet monitorurgent
swarm.completeswarm runtimeinfo
swarm.timeoutswarm runtimewarn

Notification Payload Format

All godotz.ai events follow a common JSON envelope.

{
  "event": "task.done",
  "version": "1",
  "timestamp": "2026-06-07T14:22:00Z",
  "fleet": "home-lab",
  "node": "pi-04",
  "agent": "executor-01",
  "data": {
    "task_id": 42,
    "task_title": "Update NixOS flake inputs on pi-04",
    "epic_id": 7,
    "duration_seconds": 38
  },
  "meta": {
    "swarm": "fleet-upgrade-swarm",
    "build": "v15.10.1"
  }
}

ntfy delivery maps the envelope to ntfy headers:

JSON fieldntfy header
eventX-Title
data.task_title or summarynotification body
severityX-Priority
node + agentX-Tags

omp-notify Script

omp-notify is the canonical way to emit events from hooks or custom scripts. It reads ~/.config/omp/config.yml for ntfy settings.

Usage

omp-notify [--event EVENT] [--data JSON] [--priority PRIORITY] [--title TEXT]

Examples:

# Signal task complete
omp-notify \
  --event task.done \
  --title "Task #42 done: flake inputs updated" \
  --data '{"task_id": 42, "node": "pi-04"}'

# Budget alert (urgent)
omp-notify \
  --event budget.alert \
  --title "Budget at 80% — executor-pool" \
  --priority high

# Swarm complete
omp-notify \
  --event swarm.complete \
  --title "fleet-upgrade-swarm finished in 47m" \
  --data '{"swarm": "fleet-upgrade-swarm", "duration": "47m", "cost_usd": 3.21}'

Exit codes

CodeMeaning
0Notification delivered
1Configuration error
2ntfy server unreachable
3Authentication failed

HTTP Webhooks

In addition to ntfy, godotz.ai can POST events to any HTTP endpoint.

# ~/.config/omp/config.yml
notifications:
  webhooks:
    - url: https://hooks.example.com/omp
      events: ["agent.crashed", "budget.exceeded", "node.offline"]
      secret: "whsec_your_signing_secret"
      timeout_seconds: 5
      retry: 3

The request body is the standard JSON envelope. A X-OMP-Signature header contains HMAC-SHA256(secret, body) for verification.

Verification example (Python):

import hmac, hashlib

def verify_omp_webhook(body: bytes, signature: str, secret: str) -> bool:
    expected = hmac.new(
        secret.encode(), body, hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(f"sha256={expected}", signature)

Custom Event Hooks

Register shell hooks that fire on any event:

# Register a hook for agent crashes
omp hooks add agent.crashed /opt/omp/hooks/restart-agent.sh

Hook scripts receive the full JSON envelope as $OMP_EVENT:

#!/usr/bin/env bash
# /opt/omp/hooks/restart-agent.sh
AGENT=$(echo "$OMP_EVENT" | jq -r '.agent')
NODE=$(echo "$OMP_EVENT" | jq -r '.node')
echo "Restarting $AGENT on $NODE..."
ssh "$NODE" "systemctl restart omp-agent@$AGENT"

Testing Events

Emit a test event without triggering real side-effects:

omp-notify --event test --title "OMP notification test" --dry-run
# DRY RUN: would POST to https://ntfy.sh/omp-fleet-abc123
# Payload: {"event":"test","title":"OMP notification test",...}