Metadata-Version: 2.4
Name: nornweave
Version: 0.2.0
Summary: Open-source, self-hosted Inbox-as-a-Service API for AI Agents
Project-URL: Homepage, https://github.com/DataCovey/nornweave
Project-URL: Documentation, https://nornweave.datacovey.com/docs/
Project-URL: Repository, https://github.com/DataCovey/nornweave
Project-URL: Issues, https://github.com/DataCovey/nornweave/issues
Project-URL: Changelog, https://github.com/DataCovey/nornweave/blob/main/CHANGELOG.md
Author: NornWeave Contributors
Maintainer: NornWeave Contributors
License: Apache-2.0
License-File: LICENSE
Keywords: agents,ai,api,email,inbox,llm,mcp
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Communications :: Email
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Requires-Python: >=3.14
Requires-Dist: aiosqlite>=0.22.1
Requires-Dist: alembic>=1.18.3
Requires-Dist: click>=8.3.1
Requires-Dist: cryptography>=46.0.4
Requires-Dist: email-validator>=2.3.0
Requires-Dist: fastapi>=0.128.4
Requires-Dist: html2text>=2025.4.15
Requires-Dist: httpx>=0.28.1
Requires-Dist: markdown>=3.10.1
Requires-Dist: pydantic-settings>=2.12.0
Requires-Dist: pydantic>=2.13.1
Requires-Dist: python-multipart>=0.0.22
Requires-Dist: sqlalchemy[asyncio]>=2.0.46
Requires-Dist: svix>=1.84.1
Requires-Dist: uvicorn[standard]>=0.40.0
Provides-Extra: all
Requires-Dist: aioimaplib>=2.0.1; extra == 'all'
Requires-Dist: aiosmtplib>=5.1.0; extra == 'all'
Requires-Dist: anthropic>=0.78.0; extra == 'all'
Requires-Dist: asyncpg>=0.31.0; extra == 'all'
Requires-Dist: authlib>=1.6.5; extra == 'all'
Requires-Dist: boto3>=1.42.44; extra == 'all'
Requires-Dist: fastmcp>=2.14.5; extra == 'all'
Requires-Dist: google-cloud-storage>=3.9.0; extra == 'all'
Requires-Dist: google-genai>=1.62.0; extra == 'all'
Requires-Dist: mcp>=1.26.0; extra == 'all'
Requires-Dist: openai>=2.17.0; extra == 'all'
Requires-Dist: pgvector>=0.4.2; extra == 'all'
Requires-Dist: psycopg2-binary>=2.9.11; extra == 'all'
Requires-Dist: pyjwt>=2.10.1; extra == 'all'
Requires-Dist: pypdf>=6.6.2; extra == 'all'
Requires-Dist: python-magic>=0.4.27; extra == 'all'
Requires-Dist: redis>=7.1.0; extra == 'all'
Requires-Dist: requests>=2.32.4; extra == 'all'
Provides-Extra: anthropic
Requires-Dist: anthropic>=0.78.0; extra == 'anthropic'
Provides-Extra: attachments
Requires-Dist: pypdf>=6.6.2; extra == 'attachments'
Requires-Dist: python-magic>=0.4.27; extra == 'attachments'
Provides-Extra: dev
Requires-Dist: aiosqlite>=0.22.1; extra == 'dev'
Requires-Dist: httpx>=0.28.1; extra == 'dev'
Requires-Dist: mypy>=1.19.1; extra == 'dev'
Requires-Dist: pre-commit>=4.5.1; extra == 'dev'
Requires-Dist: pytest-asyncio>=1.3.0; extra == 'dev'
Requires-Dist: pytest-cov>=7.0.0; extra == 'dev'
Requires-Dist: pytest>=9.0.2; extra == 'dev'
Requires-Dist: ruff>=0.15.0; extra == 'dev'
Provides-Extra: gcs
Requires-Dist: google-cloud-storage>=3.9.0; extra == 'gcs'
Provides-Extra: gemini
Requires-Dist: google-genai>=1.62.0; extra == 'gemini'
Provides-Extra: llm
Requires-Dist: anthropic>=0.78.0; extra == 'llm'
Requires-Dist: google-genai>=1.62.0; extra == 'llm'
Requires-Dist: openai>=2.17.0; extra == 'llm'
Provides-Extra: mcp
Requires-Dist: authlib>=1.6.5; extra == 'mcp'
Requires-Dist: fastmcp>=2.14.5; extra == 'mcp'
Requires-Dist: mcp>=1.26.0; extra == 'mcp'
Requires-Dist: pyjwt>=2.10.1; extra == 'mcp'
Requires-Dist: requests>=2.32.4; extra == 'mcp'
Provides-Extra: openai
Requires-Dist: openai>=2.17.0; extra == 'openai'
Provides-Extra: postgres
Requires-Dist: asyncpg>=0.31.0; extra == 'postgres'
Requires-Dist: psycopg2-binary>=2.9.11; extra == 'postgres'
Provides-Extra: ratelimit
Requires-Dist: redis>=7.1.0; extra == 'ratelimit'
Provides-Extra: s3
Requires-Dist: boto3>=1.42.44; extra == 's3'
Provides-Extra: search
Requires-Dist: openai>=2.17.0; extra == 'search'
Requires-Dist: pgvector>=0.4.2; extra == 'search'
Provides-Extra: smtpimap
Requires-Dist: aioimaplib>=2.0.1; extra == 'smtpimap'
Requires-Dist: aiosmtplib>=5.1.0; extra == 'smtpimap'
Description-Content-Type: text/markdown

<p align="center">
  <img src="web/static/images/Nornorna_spinner.jpg" alt="The Norns weaving fate at Yggdrasil" width="400">
</p>

<h1 align="center">NornWeave</h1>

<p align="center">
  <em>"Laws they made there, and life allotted / To the sons of men, and set their fates."</em><br>
  - Voluspa (The Prophecy of the Seeress), Poetic Edda, Stanza 20
</p>

<p align="center">
  <strong>Open-source, self-hosted Inbox-as-a-Service API for AI Agents</strong>
</p>

<p align="center">
  <a href="https://github.com/DataCovey/nornweave/actions"><img src="https://github.com/DataCovey/nornweave/workflows/CI/badge.svg" alt="CI Status"></a>
  <a href="https://github.com/DataCovey/nornweave/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-Apache--2.0-blue.svg" alt="License"></a>
</p>

---

## What is NornWeave?

Standard email APIs are stateless and built for transactional sending. **NornWeave** adds a **stateful layer** (Inboxes, Threads, History) and an **intelligent layer** (Markdown parsing, Semantic Search) to make email consumable by LLMs via REST or MCP.

In Norse mythology, the Norns (Urdr, Verdandi, and Skuld) dwell at the base of Yggdrasil, the World Tree. They weave the tapestry of fate for all beings. Similarly, NornWeave:

- Takes raw "water" (incoming email data streams)
- Weaves disconnected messages into coherent **Threads** (the Tapestry)
- Nourishes AI Agents with clean, structured context

## Features

### Foundation (The Mail Proxy)
- **Virtual Inboxes**: Create email addresses for your AI agents
- **Webhook Ingestion**: Receive emails from Mailgun, SES, SendGrid, Resend
- **IMAP/SMTP**: Poll existing mailboxes (IMAP) and send via SMTP for any provider or self-hosted server
- **Persistent Storage**: SQLite (default) or PostgreSQL with abstracted storage adapters
- **Email Sending**: Send replies through your configured provider

### Intelligence (The Agent Layer)
- **Content Parsing**: HTML to clean Markdown, cruft removal
- **Threading**: Automatic conversation grouping via email headers
- **Thread Summarization**: LLM-generated thread summaries (OpenAI, Anthropic, Gemini) for list views and token savings
- **MCP Server**: Connect directly to Claude, Cursor, and other MCP clients
- **Attachment Processing**: Extract text from PDFs and documents

### Enterprise (The Platform Layer)
- **Semantic Search**: Vector embeddings with pgvector
- **Real-time Webhooks**: Get notified of new messages
- **Rate Limiting**: Protect against runaway agents
- **Multi-Tenancy**: Organizations and projects

## Quick Start

Try NornWeave with no config: **demo mode** gives you a local sandbox and a pre-configured inbox.

```bash
pip install nornweave[mcp]
nornweave api --demo
```

API: `http://localhost:8000`. Open `/docs`, call `GET /v1/inboxes` to get the demo inbox id, then use MCP (`nornweave mcp`) to send and list messages. When you're ready for real email, set a provider and domain (see below).

### Install options

```bash
# Base (SQLite, Mailgun/SES/SendGrid/Resend)
pip install nornweave

# With IMAP/SMTP support
pip install nornweave[smtpimap]

# With PostgreSQL
pip install nornweave[postgres]

# With MCP server (recommended for agents)
pip install nornweave[mcp]

# Full
pip install nornweave[all]
```

### Real email (after demo)

Create a `.env` file and set your provider and domain:

```bash
# .env — for inbox creation with a real provider
EMAIL_PROVIDER=mailgun   # or ses, sendgrid, resend, imap-smtp
EMAIL_DOMAIN=mail.yourdomain.com
# ... plus provider-specific keys (see .env.example)
```

See [Configuration](https://nornweave.datacovey.com/docs/getting-started/configuration/) for all settings.

```bash
nornweave api
```

Data is stored in `./nornweave.db` (SQLite default).

### Using Docker (Recommended for Production)

```bash
# Clone the repository
git clone https://github.com/DataCovey/nornweave.git
cd nornweave

# Copy environment configuration and set EMAIL_DOMAIN + provider keys (see above)
cp .env.example .env

# Start the stack
docker compose up -d

# Run migrations (PostgreSQL only — SQLite tables are created automatically)
docker compose exec api alembic upgrade head
```

### Using uv (Development)

```bash
# Clone the repository
git clone https://github.com/DataCovey/nornweave.git
cd nornweave

# Install dependencies
make install-dev

# Copy environment configuration and set EMAIL_DOMAIN + provider keys (see above)
cp .env.example .env

# Run migrations (PostgreSQL only — SQLite tables are created automatically)
# make migrate

# Start the development server
make dev
```

## API Overview

### Create an Inbox

```bash
curl -X POST http://localhost:8000/v1/inboxes \
  -H "Content-Type: application/json" \
  -d '{"name": "Support Agent", "email_username": "support"}'
```

### Read a Thread

```bash
curl http://localhost:8000/v1/threads/th_123
```

Response (LLM-optimized):
```json
{
  "id": "th_123",
  "subject": "Re: Pricing Question",
  "messages": [
    { "role": "user", "author": "bob@gmail.com", "content": "How much is it?", "timestamp": "..." },
    { "role": "assistant", "author": "agent@myco.com", "content": "$20/mo", "timestamp": "..." }
  ]
}
```

### Send a Reply

```bash
curl -X POST http://localhost:8000/v1/messages \
  -H "Content-Type: application/json" \
  -d '{
    "inbox_id": "ibx_555",
    "reply_to_thread_id": "th_123",
    "to": ["client@gmail.com"],
    "subject": "Re: Pricing Question",
    "body": "Thanks for your interest! Our pricing starts at $20/mo."
  }'
```

## MCP Integration

NornWeave exposes an MCP server for direct integration with Claude, Cursor, and other MCP-compatible clients.

### Available Tools

| Tool | Description |
|------|-------------|
| `create_inbox` | Provision a new email address |
| `send_email` | Send an email (auto-converts Markdown to HTML) |
| `search_email` | Find relevant messages in your inbox |
| `wait_for_reply` | Block until a reply arrives (experimental) |

### Configure in Cursor/Claude

```bash
pip install nornweave[mcp]
```

```json
{
  "mcpServers": {
    "nornweave": {
      "command": "nornweave",
      "args": ["mcp"],
      "env": {
        "NORNWEAVE_API_URL": "http://localhost:8000"
      }
    }
  }
}
```

## Architecture

NornWeave uses a thematic architecture inspired by Norse mythology:

| Component | Name | Purpose |
|-----------|------|---------|
| Storage Layer | **Urdr** (The Well) | Database adapters (PostgreSQL, SQLite), migrations |
| Ingestion Engine | **Verdandi** (The Loom) | Webhook + IMAP ingestion, HTML→Markdown, threading, LLM thread summarization |
| Outbound | **Skuld** (The Prophecy) | Email sending, rate limiting, webhooks |
| Gateway | **Yggdrasil** | FastAPI routes, middleware, API endpoints |
| MCP | **Huginn & Muninn** | Read resources and write tools for AI agents |

## Supported Providers

| Provider | Sending | Receiving | Auto-Route Setup |
|----------|---------|-----------|------------------|
| Mailgun | yes | yes | yes |
| AWS SES | yes | yes | manual |
| SendGrid | yes | yes | yes |
| Resend | yes | yes | yes |
| IMAP/SMTP | yes (SMTP) | yes (IMAP polling) | config |

## Documentation

- [Getting Started Guide](https://nornweave.datacovey.com/docs/getting-started/)
- [API Reference](https://nornweave.datacovey.com/docs/api/)
- [Architecture Overview](https://nornweave.datacovey.com/docs/concepts/architecture/)
- [Provider Setup Guides](https://nornweave.datacovey.com/docs/guides/)

## Repository Structure

This is a monorepo:

| Directory | Purpose |
|-----------|---------|
| **`src/nornweave/`** | Main Python package: adapters (Mailgun, SES, SendGrid, Resend, SMTP/IMAP), core config, models, **huginn** (MCP resources), **muninn** (MCP tools), **skuld** (outbound/sending), **urdr** (storage, migrations), **verdandi** (ingestion, parsing, threading), **yggdrasil** (FastAPI gateway), search, storage backends |
| **`clients/python/`** | Python client SDK (`nornweave-client`) |
| **`packages/n8n-nodes-nornweave/`** | n8n community node for NornWeave |
| **`tests/`** | Test suite: `fixtures/`, `integration/`, `unit/`, `e2e/` |
| **`web/`** | Hugo documentation site (`content/docs/`) |
| **`scripts/`** | DB init, migrations, dev setup |
| **`skills/`** | Distributable AI assistant skills (e.g. `nornweave-api`) |
| **`openspec/`** | Specs (`specs/`) and change artifacts (`changes/`, `changes/archive/`) |

## Contributing

We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.

## License

NornWeave is open-source software licensed under the [Apache 2.0 License](LICENSE).

---

<p align="center">
  <sub>Image: "Nornorna spinner odet tradar vid Yggdrasil" by L. B. Hansen</sub><br>
  <sub><a href="https://commons.wikimedia.org/w/index.php?curid=164065">Public Domain</a></sub>
</p>
