# @agentvault/agentvault

End-to-end encrypted communication channel for AI agents on the [AgentVault](https://agentvault.chat) platform. Connect your agent to its owner with XChaCha20-Poly1305 encryption and Double Ratchet forward secrecy.

## What's New in v0.5.0

**Desktop Notifications** — Incoming messages now trigger native OS notifications (macOS Notification Center, Windows Toast, Linux notify-send) when using the CLI. Enabled by default — disable with `--no-notifications`.

**Webhook URL CLI Flag** (v0.4.4) — `--webhook-url` flag and `AGENTVAULT_WEBHOOK_URL` env var for programmatic webhook registration.

**Webhook Notifications** (v0.4.0) — HTTP webhook callbacks when a new message arrives, even when not connected via WebSocket.

### Upgrading

```bash
npm install @agentvault/agentvault@latest
```

No code changes required — fully backward-compatible.

---

## Installation

```bash
npm install @agentvault/agentvault
```

## Quick Start

### Option 1: CLI (Interactive)

Run directly with npx using the invite token from your AgentVault dashboard:

```bash
npx @agentvault/agentvault --token=YOUR_INVITE_TOKEN
```

The CLI will:
1. Enroll your agent with the server
2. Display a fingerprint for the owner to verify
3. Wait for owner approval
4. Establish an encrypted channel
5. Enter interactive mode where you can send/receive messages

**CLI Flags:**

| Flag | Default | Description |
|------|---------|-------------|
| `--token` | (required on first run) | Invite token from dashboard |
| `--name` | `"CLI Agent"` | Agent display name |
| `--data-dir` | `./agentvault-data` | Directory for persistent state |
| `--api-url` | `https://api.agentvault.chat` | API endpoint |
| `--webhook-url` | (none) | URL for HTTP webhook notifications |
| `--no-notifications` | (notifications on) | Disable OS desktop notifications |

Environment variables (`AGENTVAULT_INVITE_TOKEN`, `AGENTVAULT_AGENT_NAME`, `AGENTVAULT_DATA_DIR`, `AGENTVAULT_API_URL`, `AGENTVAULT_WEBHOOK_URL`, `AGENTVAULT_NO_NOTIFICATIONS`) work as alternatives to flags.

### Option 2: SDK (Programmatic)

```js
import { SecureChannel } from "@agentvault/agentvault";

const channel = new SecureChannel({
  inviteToken: "YOUR_INVITE_TOKEN",
  dataDir: "./agentvault-data",
  apiUrl: "https://api.agentvault.chat",
  agentName: "My Agent",
});

channel.on("message", (text, metadata) => {
  console.log(`Received: ${text}`);
  // Echo back
  channel.send(`You said: ${text}`);
});

channel.on("ready", () => {
  console.log("Secure channel established!");
});

await channel.start();
```

---

## Webhook Notifications (v0.4.0+)

Enable webhook notifications so your agent gets an HTTP POST when a new message arrives — useful for agents that aren't always connected via WebSocket.

### Setup

Add `webhookUrl` to your config:

```js
const channel = new SecureChannel({
  inviteToken: "YOUR_INVITE_TOKEN",
  dataDir: "./agentvault-data",
  apiUrl: "https://api.agentvault.chat",
  webhookUrl: "https://your-server.com/webhook/agentvault",
});
```

The webhook URL is registered automatically during device activation. The channel emits a `webhook_registered` event on success:

```js
channel.on("webhook_registered", ({ url, secret }) => {
  console.log(`Webhook registered at ${url}`);
  // Save the secret to verify incoming webhooks
});
```

### Webhook Payload

When the owner sends a message, your webhook endpoint receives:

```http
POST /webhook/agentvault HTTP/1.1
Content-Type: application/json
X-AgentVault-Event: new_message
X-AgentVault-Signature: sha256=<hmac-hex>

{
  "event": "new_message",
  "conversation_id": "uuid",
  "sender_device_id": "uuid",
  "message_id": "uuid",
  "timestamp": "2026-02-17T12:00:00Z"
}
```

### Verifying Webhook Signatures

Each webhook includes an HMAC-SHA256 signature in the `X-AgentVault-Signature` header. Verify it using the secret from the `webhook_registered` event:

```js
import crypto from "crypto";

function verifyWebhook(body, signature, secret) {
  const expected = "sha256=" +
    crypto.createHmac("sha256", secret).update(body).digest("hex");
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expected),
  );
}
```

---

## Configuration Reference

```ts
interface SecureChannelConfig {
  // Required
  inviteToken: string;       // Invite token from the AgentVault dashboard
  dataDir: string;           // Directory for persistent state files
  apiUrl: string;            // API endpoint (e.g., "https://api.agentvault.chat")

  // Optional
  agentName?: string;        // Display name (default: "CLI Agent")
  platform?: string;         // Platform identifier (e.g., "node")
  maxHistorySize?: number;   // Max stored messages for cross-device replay (default: 500)
  webhookUrl?: string;       // Webhook URL for new message notifications (v0.4.0+)

  // Callbacks (alternative to event listeners)
  onMessage?: (text: string, metadata: MessageMetadata) => void;
  onStateChange?: (state: ChannelState) => void;
}
```

## Events

| Event | Payload | Description |
|-------|---------|-------------|
| `message` | `(text: string, metadata: MessageMetadata)` | Owner sent a message |
| `ready` | none | WebSocket connected, channel operational |
| `state` | `(state: ChannelState)` | State transition occurred |
| `error` | `(error: Error)` | Fatal error |
| `webhook_registered` | `({ url: string, secret: string })` | Webhook registered (v0.4.0+) |

## Channel States

`idle` → `enrolling` → `polling` → `activating` → `connecting` → `ready`

If disconnected: `ready` → `disconnected` → `connecting` → `ready` (auto-reconnect)

## API

| Method | Description |
|--------|-------------|
| `start()` | Initialize, enroll, and connect |
| `send(text)` | Encrypt and send message to all owner devices |
| `stop()` | Gracefully disconnect |

| Property | Description |
|----------|-------------|
| `state` | Current channel state |
| `deviceId` | Agent's device ID (after enrollment) |
| `fingerprint` | Device fingerprint for verification |
| `conversationId` | Primary conversation ID |
| `conversationIds` | All active conversation IDs (multi-device) |
| `sessionCount` | Number of active encrypted sessions |

## Multi-Device Support

AgentVault supports multiple owner devices (e.g., desktop + mobile). The channel automatically:
- Maintains independent encrypted sessions per owner device
- Fans out `send()` to all active sessions
- Stores message history for cross-device replay (up to `maxHistorySize`)
- Replays history when a new device connects

No additional configuration needed — multi-device is handled transparently.

## Running as a Service

The agent process must stay running to receive messages and desktop notifications. Use [pm2](https://pm2.keymetrics.io/) to keep it alive:

```bash
# Install pm2 globally
npm install -g pm2

# Start your agent as a background service
pm2 start npx --name "my-agent" -- @agentvault/agentvault \
  --token=YOUR_TOKEN --name="My Agent"

# View logs
pm2 logs my-agent

# Auto-restart on crash
pm2 save

# Stop the agent
pm2 stop my-agent
```

pm2 keeps the process running if the terminal closes and auto-restarts on crashes. Desktop notifications continue to work as long as pm2 was started from your desktop session.

For headless servers (no desktop), use `--no-notifications` and configure `--webhook-url` instead.

## Security

- **XChaCha20-Poly1305** symmetric encryption (192-bit nonces)
- **X3DH** key agreement (Ed25519 + X25519)
- **Double Ratchet** for forward secrecy — old keys deleted after use
- **Zero-knowledge server** — the server never sees plaintext
- **HMAC-SHA256** webhook signatures for authenticity verification

## License

MIT
