> ## Documentation Index
> Fetch the complete documentation index at: https://docs.agentvault.chat/llms.txt
> Use this file to discover all available pages before exploring further.

# Plugin Integration Guide

> Complete guide to integrating AgentVault into your agent with the npm plugin.

# Plugin Integration Guide

This guide walks you through integrating the `@agentvault/agentvault` library directly into your agent's codebase for full programmatic control over the secure channel.

<Note>
  **Not a developer?** The [Quick Start](/getting-started/quick-start) guide connects your agent with a single terminal command, no code required.
</Note>

**What you will accomplish:**

* Install and configure the agent plugin
* Enroll your agent with an invite token
* Approve the agent and establish an encrypted channel
* Send and receive end-to-end encrypted messages

**Time required:** \~10 minutes

## Prerequisites

* An AgentVault account at [agentvault.chat](https://agentvault.chat)
* Node.js 18+ on the machine where your agent runs
* A Node.js or TypeScript project for your agent

***

<Steps>
  <Step title="Generate an invite token">
    1. Log in to [agentvault.chat](https://app.agentvault.chat)
    2. Navigate to the **Invites** tab
    3. Enter a name for your agent (e.g., "Research Agent")
    4. Tap **Generate Invite**
    5. **Copy the token immediately** — it is shown only once and expires in 10 minutes

    The token looks like: `av_tok_abc123def456...`

    <Warning>
      Do not share invite tokens publicly. Anyone with the token can enroll a device to your account.
    </Warning>
  </Step>

  <Step title="Install the plugin">
    In your agent's project directory:

    ```bash theme={null}
    npm install @agentvault/agentvault
    ```

    This package handles all cryptography, enrollment, and WebSocket communication automatically.
  </Step>

  <Step title="Add the secure channel to your agent">
    Create a file or add to your existing entry point:

    <CodeGroup>
      ```typescript ESM (TypeScript / ES Modules) theme={null}
      import { SecureChannel } from "@agentvault/agentvault";

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

        onMessage: (plaintext, metadata) => {
          console.log(`Owner says: ${plaintext}`);
          // Process with your agent logic, then respond:
          channel.send("Got it! Working on that now...");
        },

        onStateChange: (state) => {
          console.log(`Channel state: ${state}`);
        },
      });

      await channel.start();
      ```

      ```javascript CommonJS theme={null}
      async function main() {
        const { SecureChannel } = await import("@agentvault/agentvault");

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

          onMessage: (plaintext, metadata) => {
            console.log(`Owner says: ${plaintext}`);
            channel.send("Got it! Working on that now...");
          },

          onStateChange: (state) => {
            console.log(`Channel state: ${state}`);
          },
        });

        await channel.start();
      }

      main();
      ```
    </CodeGroup>
  </Step>

  <Step title="Run your agent and approve it">
    Start your agent:

    ```bash theme={null}
    node your-agent.js
    ```

    You will see:

    ```
    Channel state: enrolling
    Channel state: polling
    ```

    Now go to the **Agents** tab at [agentvault.chat](https://app.agentvault.chat), find the device marked **Pending**, verify the fingerprint matches, and tap **Approve**.

    Your agent's output will update:

    ```
    Channel state: activating
    Channel state: connecting
    Channel state: ready
    ```

    The secure channel is now live with end-to-end encryption.
  </Step>
</Steps>

***

## Full Working Example

A complete echo agent that responds to every message:

```typescript theme={null}
import { SecureChannel } from "@agentvault/agentvault";

const channel = new SecureChannel({
  inviteToken: process.env.AGENTVAULT_INVITE_TOKEN,
  dataDir: "./agentvault-data",
  apiUrl: "https://api.agentvault.chat",
  agentName: "Echo Agent",

  onMessage: (plaintext, metadata) => {
    console.log(`[${new Date(metadata.timestamp).toLocaleTimeString()}] Owner: ${plaintext}`);
    channel.send(`Echo: ${plaintext}`);
  },

  onStateChange: (state) => {
    if (state === "polling") {
      console.log(`Fingerprint: ${channel.fingerprint}`);
      console.log("Waiting for owner to approve in the dashboard...");
    }
    if (state === "ready") {
      console.log("Secure channel is live!");
      channel.send("Agent is online and ready.");
    }
    if (state === "disconnected") {
      console.log("Connection lost — reconnecting automatically...");
    }
  },
});

await channel.start();

process.on("SIGINT", async () => {
  console.log("Shutting down...");
  await channel.stop();
  process.exit(0);
});
```

Run it:

```bash theme={null}
AGENTVAULT_INVITE_TOKEN="av_tok_YOUR_TOKEN" node echo-agent.js
```

***

## Configuration Reference

### Constructor Options

| Option          | Required        | Default  | Description                                        |
| --------------- | --------------- | -------- | -------------------------------------------------- |
| `inviteToken`   | Yes (first run) | --       | One-time invite token from the dashboard           |
| `dataDir`       | Yes             | --       | Directory for persistent state (keys, ratchet)     |
| `apiUrl`        | Yes             | --       | AgentVault API URL (`https://api.agentvault.chat`) |
| `agentName`     | No              | --       | Display name shown to the owner                    |
| `platform`      | No              | `"node"` | Platform identifier                                |
| `onMessage`     | No              | --       | Callback for incoming messages                     |
| `onStateChange` | No              | --       | Callback for state transitions                     |

### Channel States

| State          | Description                                        |
| -------------- | -------------------------------------------------- |
| `idle`         | Channel created, `start()` not yet called          |
| `enrolling`    | Submitting enrollment to server                    |
| `polling`      | Waiting for owner approval (polls every 5 seconds) |
| `activating`   | Owner approved — performing key exchange           |
| `connecting`   | Opening encrypted WebSocket connection             |
| `ready`        | Fully connected — can send and receive messages    |
| `disconnected` | Connection lost — reconnecting automatically       |
| `error`        | Fatal error (revoked, invalid token, etc.)         |

### Properties and Methods

<Tabs>
  <Tab title="Properties">
    ```typescript theme={null}
    channel.state          // Current channel state
    channel.deviceId       // Agent's device UUID (after enrollment)
    channel.fingerprint    // 8-character fingerprint for verification
    channel.conversationId // Conversation UUID (after activation)
    ```
  </Tab>

  <Tab title="Methods">
    ```typescript theme={null}
    await channel.start()          // Begin lifecycle: enroll -> approve -> connect
    await channel.send("message")  // Send an encrypted message
    await channel.stop()           // Gracefully disconnect
    ```
  </Tab>

  <Tab title="Events">
    ```typescript theme={null}
    channel.on("ready", () => {})
    channel.on("message", (plaintext, metadata) => {})
    channel.on("state", (state) => {})
    channel.on("error", (error) => {})
    ```
  </Tab>
</Tabs>

***

## Persistence and Restarts

After the first enrollment, your agent reconnects automatically on restart — no new invite needed.

```bash theme={null}
# First run: uses invite token, enrolls, waits for approval
node my-agent.js

# Subsequent runs: loads saved state, reconnects immediately
node my-agent.js
```

<Tip>
  The `dataDir` folder contains your agent's encrypted identity and ratchet state. **Back it up.** If lost, you will need to generate a new invite and re-enroll. If running in Docker, mount it as a volume.
</Tip>

***

## What Happens Under the Hood

The plugin handles the full cryptographic lifecycle automatically:

<Accordion title="Encryption details">
  1. **Key Generation** — Ed25519 identity keys and X25519 ephemeral keys are generated locally on your agent's machine
  2. **Enrollment** — Your agent proves possession of the private key and registers with the server
  3. **Key Exchange** — After approval, X3DH (Extended Triple Diffie-Hellman) key agreement establishes a shared secret with the owner
  4. **Double Ratchet** — Every message uses a fresh encryption key (forward secrecy). Old keys are deleted after decryption.
  5. **WebSocket** — Real-time bidirectional messaging with automatic reconnection on network interruption
  6. **Persistence** — Keys and ratchet state are saved to `dataDir` so your agent survives restarts without re-enrolling

  The server **never** sees message content. Messages are encrypted before leaving your machine and only decrypted on the other end.
</Accordion>

***

## Troubleshooting

<Accordion title="'Channel state: error' immediately after start">
  The invite token is invalid or expired. Generate a new one from the **Invites** tab in the dashboard. Tokens expire after 10 minutes.
</Accordion>

<Accordion title="Agent stuck in 'polling' state">
  The owner has not approved the device yet. Check the **Agents** tab at [agentvault.chat](https://app.agentvault.chat) and approve the pending device.
</Accordion>

<Accordion title="'disconnected' and 'connecting' loop">
  This indicates a network issue between your agent and the server. Verify that `https://api.agentvault.chat` is reachable from your agent's machine. The agent will continue retrying automatically.
</Accordion>

<Accordion title="Agent works once but fails after restart">
  Make sure the `dataDir` directory is writable and persists across restarts. If running in Docker, mount it as a volume:

  ```bash theme={null}
  docker run -v ./agentvault-data:/app/agentvault-data my-agent
  ```
</Accordion>

<Accordion title="Messages not arriving">
  Both sides must be connected (agent in `ready` state, owner has the chat open). Messages sent while disconnected are queued and delivered on reconnect.
</Accordion>

***

## Security Notes

* All messages are encrypted with **XChaCha20-Poly1305** (AEAD)
* The server stores only ciphertext — it cannot read your messages
* Each message derives a unique key via the **Double Ratchet** protocol (forward secrecy)
* Verify fingerprints during approval to prevent man-in-the-middle attacks
* Revoking a device from the dashboard immediately disconnects it and invalidates its keys

***

## Next Steps

<CardGroup cols={2}>
  <Card title="Architecture Overview" icon="sitemap" href="/architecture/overview">
    Understand the full system architecture and data flow.
  </Card>

  <Card title="Security Model" icon="shield" href="/architecture/zero-knowledge">
    Deep dive into the zero-knowledge design and threat model.
  </Card>
</CardGroup>
