Skip to main content

Norns Agent

Core AI agent backend providing agentic capabilities with long-term memory.


Overview

Norns Agent is a Python/FastAPI service that implements the core agent logic, including the Raven Model memory system.

PropertyValue
Containernorns-agent
URLnorns-pm.ravenhelm.dev
Port8000 (internal: 3901)
Config~/ravenhelm/docs/AI-ML-Platform/norns-agent/
Source~/ravenhelm/docs/AI-ML-Platform/norns-agent/agent/

Architecture

┌─────────────────────────────────────────────────────────────┐
│ NORNS AGENT │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Huginn │───▶│ Context │───▶│ Muninn │ │
│ │ (State/Redis)│ │ (Identity) │ │ (Memory) │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ │ │ │ │
│ └───────────────────┼───────────────────┘ │
│ ▼ │
│ ┌──────────────┐ │
│ │ LangGraph │ │
│ │ Agent │ │
│ └──────────────┘ │
│ │ │
│ ┌───────────────────┼───────────────────┐ │
│ ▼ ▼ ▼ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Tools │ │ Claude │ │ Langfuse │ │
│ │ (HA, Cal...) │ │ API │ │ (Trace) │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────────────┘

See Norns Memory System for detailed memory architecture.


Communication Channels

Norns supports multiple communication channels, all routing through the same agent graph:

ChannelDocumentationDescription
SlackSlack IntegrationDirect messages and mentions
VoiceNorns TelephonyPhone calls via Twilio/LiveKit
WhatsAppNorns WhatsAppWhatsApp messaging via Twilio

All channels share:

  • Same LangGraph agent graph
  • Same tool capabilities
  • Same memory system (Muninn)
  • Unified session management

Capabilities

ToolDescription
task_managerCRUD operations on tasks
project_managerProject management
calendarGoogle Calendar integration
home_assistantSmart home control
grocyInventory management
observabilityQuery Grafana/Loki/Prometheus
slackPost messages to Slack
memoryRecall and search past interactions
phone_callMake outbound phone calls
smsSend SMS messages via Twilio

Memory System

The agent implements the Raven Model - a three-plane cognitive architecture:

PlaneNamePurpose
StateHuginnReal-time session state (Redis)
IdentityContextUser identity and permissions
MemoryMuninnLong-term episodic and semantic memory

Key Features:

  • Vector embeddings via Ollama (nomic-embed-text)
  • Semantic search across past interactions
  • Automatic pattern extraction and learning
  • Knowledge entity graph

See Norns Memory System for complete documentation.


API Endpoints

Core API

EndpointMethodDescription
/healthGETHealth check
/api/chatPOSTSend chat message
/api/tasksGET/POSTTask management
/api/projectsGET/POSTProject management
/api/memory/recallPOSTSearch memories

Channel Webhooks

EndpointMethodDescription
/slack/eventsPOSTSlack event webhook
/telephony/webhookPOSTTwilio voice webhook
/whatsapp/webhookPOSTWhatsApp inbound messages
/whatsapp/statusPOSTWhatsApp delivery status

WhatsApp API

EndpointMethodDescription
/api/whatsapp/sendPOSTSend proactive template message
/api/whatsapp/templatesGETList configured templates
/api/whatsapp/session/{phone}GETCheck session window status

Quick Commands

# View logs
docker logs -f norns-agent

# Restart
docker restart norns-agent

# Shell access
docker exec -it norns-agent bash

# Test health
curl https://norns-pm.ravenhelm.dev/health

# Check memory stats
docker exec -i postgres psql -U ravenhelm -d ravenmaskos -c \
"SELECT COUNT(*) as memories FROM episodic_memories;"

Configuration

Environment Variables

environment:
# Database
- DB_HOST=postgres
- DB_PORT=5432
- DB_NAME=ravenmaskos
- DB_USER=ravenhelm
- DB_PASSWORD=${POSTGRES_PASSWORD}

# Redis
- REDIS_HOST=redis
- REDIS_PORT=6379
- REDIS_PASSWORD=${REDIS_PASSWORD}

# LLM Providers
- ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
- OPENAI_API_KEY=${OPENAI_API_KEY}
- OLLAMA_URL=http://ollama:11434

# Embeddings
- EMBEDDING_PROVIDER=auto
- OLLAMA_EMBED_MODEL=nomic-embed-text

# Langfuse
- LANGFUSE_HOST=http://langfuse-web:3000
- LANGFUSE_PUBLIC_KEY=${LANGFUSE_PUBLIC_KEY}
- LANGFUSE_SECRET_KEY=${LANGFUSE_SECRET_KEY}

# Slack
- SLACK_BOT_TOKEN=${SLACK_BOT_TOKEN}

# Twilio (Voice + WhatsApp)
- TWILIO_ACCOUNT_SID=${TWILIO_ACCOUNT_SID}
- TWILIO_AUTH_TOKEN=${TWILIO_AUTH_TOKEN}
- TWILIO_WHATSAPP_NUMBER=${TWILIO_WHATSAPP_NUMBER}

# WhatsApp Templates
- WA_TEMPLATE_TASK_REMINDER=${WA_TEMPLATE_TASK_REMINDER:-}
- WA_TEMPLATE_DAILY_BRIEFING=${WA_TEMPLATE_DAILY_BRIEFING:-}
- WA_TEMPLATE_CALENDAR_REMINDER=${WA_TEMPLATE_CALENDAR_REMINDER:-}
- WA_TEMPLATE_TASK_COMPLETE=${WA_TEMPLATE_TASK_COMPLETE:-}
- WA_TEMPLATE_WEEKLY_REVIEW=${WA_TEMPLATE_WEEKLY_REVIEW:-}

# Integrations
- HOMEASSISTANT_URL=http://homeassistant:8123
- HOMEASSISTANT_TOKEN=${HOMEASSISTANT_TOKEN}

Slack Integration

Norns responds to messages in Slack via "The Norns" bot:

  1. User mentions @The Norns in Slack
  2. Slack sends event to /slack/events
  3. Agent processes request with full context
  4. Memory is recorded for future recall
  5. Response posted back to thread

WhatsApp Integration

Norns responds to WhatsApp messages via Twilio:

  1. User sends WhatsApp message
  2. Twilio sends webhook to /whatsapp/webhook
  3. Agent processes request with full context
  4. Memory is recorded for future recall
  5. Response sent back via Twilio API

Key features:

  • 24-hour session window tracking
  • Proactive templates for scheduled messages
  • Rich messaging support (buttons, lists)

See Norns WhatsApp Channel for full documentation.


Troubleshooting

Issue: Agent Not Responding

Symptoms: No response to chat or Slack messages

Diagnosis:

docker logs norns-agent | tail -50
curl https://norns-pm.ravenhelm.dev/health

Solutions:

  1. Check API keys are valid
  2. Verify database connectivity
  3. Check Langfuse is reachable

Issue: Tool Execution Failed

Symptoms: Agent responds but tool fails

Diagnosis:

# Check Langfuse for trace details
docker logs norns-agent 2>&1 | grep -A 10 "Error"

Solutions:

  1. Verify integration credentials
  2. Check target service is running
  3. Review Langfuse traces for details

Issue: Memory Not Working

See Norns Memory System Troubleshooting

Issue: WhatsApp Not Working

See WhatsApp Channel Runbook


Social Domain

The Social domain handles all communication tasks including Slack, phone calls, and SMS.

Workers

WorkerDescriptionRequires
SlackMessagingWorkerSend Slack messages and DMsSLACK_BOT_TOKEN
PhoneCallWorkerMake outbound callsTELEPHONY_URL, NORNS_API_KEY
SMSWorkerSend SMS via TwilioTWILIO_ACCOUNT_SID, TWILIO_AUTH_TOKEN, TWILIO_FROM_NUMBER

Routing

The classifier routes messages to the SOCIAL domain when they involve:

  • Sending messages (Slack, SMS)
  • Making phone calls
  • Communication with people

Examples:

  • "Send John a message on Slack" → SOCIAL → SlackMessagingWorker
  • "Call Sarah" → SOCIAL → PhoneCallWorker
  • "Text mom that I'm on my way" → SOCIAL → SMSWorker

SMS Worker

Sends SMS via Twilio REST API:

# Environment variables
TWILIO_ACCOUNT_SID=<account_sid>
TWILIO_AUTH_TOKEN=<auth_token>
TWILIO_FROM_NUMBER=+17372143330

# Example usage
await sms_worker.execute(
state=agent_state,
action="text mom I'll be home soon",
slack_user_id="U123456"
)

Phone number resolution:

  1. Checks user's phone_numbers table for contact names
  2. Falls back to E.164 parsing for explicit numbers
  3. Rejects unknown contacts for safety

Multi-Task Execution

Norns supports compound requests that involve multiple independent tasks.

How It Works

  1. Classification: The classifier identifies compound requests and creates action_items
  2. Parallel Execution: Tasks are dispatched concurrently using asyncio.as_completed()
  3. Streaming: Each task streams its own progress independently
  4. Aggregation: Results are combined for the final response

Example

Request: "Add eggs to the shopping list, check my calendar for tomorrow, and send John a message"

Decomposition:

{
"requires_iteration": true,
"action_items": [
{"action": "add eggs to shopping list", "domain": "task"},
{"action": "check calendar for tomorrow", "domain": "calendar"},
{"action": "send John a message", "domain": "social"}
]
}

Execution: All three tasks execute in parallel, streaming their progress as they complete.

Routing Rules

The classifier determines:

  • requires_iteration: false → Single domain handles the request
  • requires_iteration: true → Multiple domains execute in parallel

Compound request patterns:

  • "X and Y and Z"
  • "Do A, then B"
  • "First X, also Y"