Comergence — Domain Registry Protocol¶
How any constituent registers itself with Comergence.
Design Principles¶
- Self-registering — deploy an agent, get a tile. No manual dashboard configuration.
- Self-describing — the manifest tells the system everything it needs to know
- Hierarchical — domains contain sub-domains contain constituents, to any depth
- Ownership — every domain has an agent owner and optionally a human owner
- Evolvable — manifests can be updated at runtime; the system re-reads and adapts
The Manifest File¶
Every domain registers by placing an comergence.json file in its workspace root. The signal bus watches for these files. A new file = a new tile. An updated file = the tile morphs. A deleted file = the tile disappears.
{
"domain": "ai-system.agents.maxrow",
"name": "Maxrow",
"description": "Main orchestrator agent. System health, memory, docs, drift.",
"icon": "🔴",
"version": "1",
"owner": {
"agent": "main",
"workspace": "/home/clawuser/clawd",
"human": "jerry"
},
"parent": "ai-system.agents",
"children": [],
"dataSources": [
{
"type": "session-files",
"path": "~/.openclaw/agents/main/sessions/",
"watch": true
},
{
"type": "memory-files",
"path": "/home/clawuser/clawd/memory/",
"watch": true
},
{
"type": "cron-config",
"path": "~/.openclaw/cron/",
"watch": true
}
],
"healthRules": [
{
"id": "heartbeat",
"description": "Heartbeat received within expected window",
"check": "last_signal_age < 600",
"onFail": "amber",
"code": "agent.heartbeat_missed"
},
{
"id": "cron-health",
"description": "No consecutive cron failures",
"check": "cron_consecutive_errors == 0",
"onFail": "amber",
"code": "agent.cron_failed"
},
{
"id": "cost-spike",
"description": "7-day API cost within threshold",
"check": "cost_7d < 25.00",
"onFail": "amber",
"code": "agent.cost_spike"
}
],
"notifications": {
"amber": [
{ "target": "human:jerry", "channel": "telegram" }
],
"red": [
{ "target": "human:jerry", "channel": "telegram" },
{ "target": "agent:main", "prompt": "An agent in the AI System domain has gone red. Investigate and report." }
]
},
"actions": [
{
"id": "view-sessions",
"label": "View Sessions",
"type": "drill-down",
"target": "ai-system.agents.maxrow.sessions"
},
{
"id": "view-memory",
"label": "View Memory",
"type": "drill-down",
"target": "ai-system.agents.maxrow.memory"
},
{
"id": "restart-gateway",
"label": "Restart Gateway",
"type": "agent-task",
"agent": "main",
"prompt": "Run the gateway restart procedure using the gateway-restart skill.",
"requiresConfirmation": true
}
],
"publishInterval": 60,
"standalone": true
}
Field Reference¶
Identity¶
| Field | Type | Required | Description |
|---|---|---|---|
domain |
string | ✅ | Dot-namespaced path (e.g., production.work-centers.cnc-3) |
name |
string | ✅ | Human-readable display name |
description |
string | ✅ | One-line description of what this domain represents |
icon |
string | ✅ | Emoji icon displayed on tile |
version |
string | ✅ | Manifest version (increment on breaking changes) |
Ownership¶
| Field | Type | Required | Description |
|---|---|---|---|
owner.agent |
string | ✅ | Agent ID responsible for this domain's health signals |
owner.workspace |
string | ✅ | Filesystem path to the agent's workspace |
owner.human |
string | — | Human identifier paired with this domain |
Hierarchy¶
| Field | Type | Required | Description |
|---|---|---|---|
parent |
string | — | Parent domain path. Null = top-level domain |
children |
string[] | — | Child domain paths. Empty = leaf node. Can be populated dynamically by the agent |
Data Sources¶
Declares where the agent reads data to compute health. The signal bus uses this to understand what filesystem paths to watch for change-triggered re-evaluation.
| Type | Description |
|---|---|
session-files |
OpenClaw JSONL session files |
memory-files |
Agent memory directory |
cron-config |
OpenClaw cron job config |
netsuite-api |
NetSuite SuiteQL (agent polls) |
hubspot-api |
HubSpot API (agent polls) |
file-watch |
Arbitrary file or directory |
sensor |
Physical sensor (via Home Assistant) |
manual |
Agent sets state directly from its own reasoning |
Health Rules¶
Rules the agent evaluates to determine its status. Rules are evaluated in order; the worst result wins.
{
"id": "rule-id",
"description": "Human readable description",
"check": "expression",
"onFail": "amber | red",
"code": "signal.code.to.publish"
}
Check expressions are simple and declarative. The agent's publisher module evaluates them against collected metrics. Complex logic stays in the agent's own code — the manifest captures the threshold.
Notifications¶
Who gets notified at each severity level. Multiple targets supported.
{
"amber": [
{ "target": "human:jerry", "channel": "telegram" },
{ "target": "agent:main", "prompt": "Context for investigation..." }
],
"red": [
{ "target": "human:jerry", "channel": "telegram" },
{ "target": "human:michael", "channel": "telegram" },
{ "target": "physical:ha:shop-andon-light", "state": "red" }
]
}
Target formats:
- human:{id} — person, routed via their preferred channel
- agent:{id} — spawns a task on that agent with the provided prompt
- physical:ha:{entity-id} — Home Assistant entity
- channel:{name} — broadcast to a channel (Slack, Telegram group)
Actions¶
Actions available from this domain's tile in the UI. Actions can be triggered manually by a human or automatically on signal publish (via auto: true in the signal object).
Action types:
- drill-down — navigate to a child domain in the UI
- agent-task — spawn an agent task with context
- message — send a message to a human or channel
- physical — trigger a Home Assistant entity
- external — call a webhook or API
Domain Path Naming Convention¶
Paths are dot-namespaced, lowercase, hyphen-separated words.
[top-domain].[sub-domain].[constituent].[detail]
Examples:
production
production.work-centers
production.work-centers.cnc-3
ai-system
ai-system.agents
ai-system.agents.maxrow
ai-system.crons
ai-system.crons.system-orchestrator
integrations.netsuite
integrations.shopify
sales.pipeline
sales.pipeline.commercial
fulfillment.open-orders
Top-Level Domains (Stikwood)¶
comergence/
├── production/ → Sawyer (production agent)
│ ├── work-centers/ → per-machine agents (future)
│ ├── scheduling/
│ └── quality/
├── fulfillment/ → Sawyer
│ ├── open-orders/
│ ├── shipping/
│ └── inventory/
├── sales/ → Maven
│ ├── pipeline/
│ ├── accounts/
│ └── specs/
├── marketing/ → Maven
│ ├── campaigns/
│ ├── email/
│ └── social/
├── finance/ → TBD agent
│ ├── accounts-receivable/
│ ├── cash-flow/
│ └── budget/
├── ai-system/ → Maxrow
│ ├── agents/ → per-agent tiles
│ ├── crons/ → per-cron tiles
│ ├── nodes/ → VPS, mccall-home
│ ├── channels/ → Telegram, Slack
│ └── integrations/ → API health per system
└── home/ → Gus/Luma
├── climate/
├── lighting/
├── security/
└── audio/
Discovery Mechanism¶
The signal bus watches a discovery directory for manifests:
~/.comergence/
registry/
ai-system.agents.maxrow.json ← manifest files
ai-system.agents.maven.json
production.json
fulfillment.json
...
signals/
[live signal files]
history/
[archived signals]
Agent startup sequence:
1. Agent reads its comergence.json from workspace
2. Agent copies it to ~/.comergence/registry/{domain}.json
3. Signal bus detects new file via chokidar
4. Dashboard receives new domain → renders tile
5. Agent begins publishing signals to ~/.comergence/signals/
On shutdown or agent deregistration:
1. Agent removes its registry file
2. Signal bus detects removal
3. Dashboard marks tile as offline
The Human-Agent Pair Manifest¶
For work center agents paired with a human operator, the manifest extends with pairing info:
{
"domain": "production.work-centers.cnc-3",
"name": "CNC-3",
"icon": "⚙️",
"owner": {
"agent": "cnc3-agent",
"human": "operator-mike"
},
"pairing": {
"human": {
"id": "operator-mike",
"name": "Mike",
"preferredChannel": "telegram",
"telegramId": "123456789",
"role": "CNC Operator",
"shift": "06:00-14:00"
},
"interface": "mobile",
"guidanceStyle": "brief",
"escalationChain": ["operator-mike", "michael", "jerry"]
}
}
The pairing.escalationChain defines who gets contacted if the paired human doesn't acknowledge an alert within a configurable window.
Versioning & Evolution¶
Manifests include a version field. When the agent publishes an updated manifest:
- The registry replaces the old version
- The dashboard diffs and re-renders changed tiles
- Historical signals from the old version remain archived
Breaking changes (domain path changes, renamed children) increment version. The dashboard handles graceful migration — old tiles fade to unknown as new tiles appear.
The registry is the map. The signals are the territory. The agents keep them in sync.