NATS Ontology
Complete reference for NATS subject hierarchy, message formats, and patterns
Table of Contents
Overview
This document defines the NATS subject hierarchy, message formats, and patterns used in the ArtCafe.ai platform. It serves as the authoritative reference for developers building agents and applications on our infrastructure.
Core Principles
1. Tenant Isolation
All subjects include tenant ID for complete isolation
2. Predictable Patterns
Developers can construct subjects without lookups
3. Wildcard Support
Leverage NATS wildcards for flexible subscriptions
4. Security by Default
No sensitive data in subject names
Subject Hierarchy
Base Pattern
tenant.{tenant_id}.{category}.{subcategory}.{specifics}1. Channel Communication
Primary mechanism for agent-to-agent communication within an organization.
tenant.{tenant_id}.channel.{channel_id}Examples:
tenant.org-123.channel.system-notifications tenant.org-123.channel.task-queue tenant.org-123.channel.analytics-events
Wildcards:
tenant.org-123.channel.* # All channels for a tenant tenant.org-123.channel.task-* # All task-related channels
2. Agent-Specific Topics
Direct communication and agent lifecycle events.
# Agent status and presence
tenant.{tenant_id}.agents.{agent_id}.status
tenant.{tenant_id}.agents.{agent_id}.heartbeat
# Direct messaging to specific agent
tenant.{tenant_id}.agents.{agent_id}.direct
# Agent metrics and telemetry
tenant.{tenant_id}.agents.{agent_id}.metricsWildcards:
tenant.org-123.agents.*.status # Status of all agents tenant.org-123.agents.> # All agent-related messages
3. System Topics
Platform-level events and control messages.
# System-wide events
tenant.{tenant_id}.system.events.{event_type}
# Platform notifications
tenant.{tenant_id}.system.notifications
# Agent discovery
tenant.{tenant_id}.system.discovery.request
tenant.{tenant_id}.system.discovery.responseMessage Formats
Standard Message Envelope
All messages MUST include this envelope structure:
{
"id": "msg-uuid-v4",
"timestamp": "2024-01-01T00:00:00Z",
"version": "1.0",
"tenant_id": "org-123",
"source": {
"agent_id": "agent-001",
"type": "agent|system|user"
},
"type": "message|event|command|query|response",
"correlation_id": "optional-correlation-id",
"reply_to": "optional-reply-subject",
"payload": {
// Actual message content
}
}Channel Message
{
"type": "message",
"payload": {
"content": "Message content",
"metadata": {
"priority": "normal|high|low",
"ttl": 3600
}
}
}Task Assignment
{
"type": "command",
"payload": {
"task_id": "task-uuid",
"task_type": "analysis",
"data": {},
"constraints": {
"timeout": 300,
"max_retries": 3
}
}
}Status Update
{
"type": "event",
"payload": {
"status": "online|offline|busy",
"capabilities": ["nlp", "vision"],
"metadata": {
"version": "1.0.0",
"uptime": 3600
}
}
}Heartbeat
{
"type": "event",
"payload": {
"heartbeat": true,
"timestamp": "2024-01-01T00:00:00Z",
"metrics": {
"cpu": 45.2,
"memory": 1024,
"tasks_processed": 150
}
}
}Examples
Simple Agent Communication
# Agent 1 publishes a task
await nats.publish(
"tenant.org-123.channel.task-queue",
{
"id": str(uuid4()),
"timestamp": datetime.utcnow().isoformat(),
"type": "message",
"source": {"agent_id": "agent-001", "type": "agent"},
"payload": {
"task": "analyze_document",
"document_id": "doc-123"
}
}
)
# Agent 2 receives and responds
@nats.subscribe("tenant.org-123.channel.task-queue")
async def handle_task(msg):
if can_handle(msg.payload.task):
# Process task
result = await process_task(msg.payload)
# Publish result
await nats.publish(
f"tenant.org-123.results.{msg.id}",
{
"id": str(uuid4()),
"type": "response",
"correlation_id": msg.id,
"payload": result
}
)Monitoring All Agents
# Dashboard subscribes to all agent status updates
@nats.subscribe("tenant.org-123.agents.*.status")
async def track_agent_status(msg):
agent_id = msg.subject.split('.')[3]
status = msg.payload.status
update_dashboard(agent_id, status)Request-Reply Pattern
# Make request with reply subject
reply_inbox = f"_INBOX.{uuid4()}"
await nats.subscribe(reply_inbox, max_msgs=1)
await nats.publish(
"tenant.org-123.service.calculator",
{
"type": "query",
"reply_to": reply_inbox,
"payload": {"operation": "add", "a": 5, "b": 3}
}
)
# Service responds to reply_to
response = await nats.request(reply_inbox, timeout=5.0)Best Practices
✓ Do
- • Always include tenant_id in subjects
- • Use meaningful channel names
- • Leverage wildcards for subscriptions
- • Include correlation_id for tracking
- • Set TTL on time-sensitive messages
- • Monitor subscription count
✗ Don't
- • Never include PII in subjects
- • Never expose private keys
- • Avoid UUID-based channel names
- • Don't exceed 255 char subjects
- • Avoid large message payloads (>1MB)
- • Don't create excessive subscriptions
Performance Guidelines
Subject Length
- • Keep subjects under 255 characters
- • Use abbreviations for common terms if needed
Message Size
- • Standard messages: < 1MB
- • Large payloads: Use object storage + reference
- • Streaming: Use chunked messages with sequence numbers
Subscription Limits
- • Per agent: Maximum 100 subscriptions
- • Use wildcards to reduce subscription count
- • Prefer broad subscriptions with client-side filtering
Ready to Build?
Start building your agents with our comprehensive framework and tools.