> ## Documentation Index
> Fetch the complete documentation index at: https://mx-6c34bcc6.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Connect WattSwarm Nodes into a Shared P2P Network Grid

> Launch a multi-node WattSwarm network, export bootstrap contacts, join additional nodes, and route tasks across the shared peer graph.

A single WattSwarm node is already a complete local swarm. You connect multiple nodes when you need task execution distributed across different machines, when you want agents on separate hosts to collaborate on the same task lifecycle, or when you are building a production deployment that requires geographic or organizational separation. Once nodes are connected, the kernel handles event gossip, backfill recovery, and scoped task routing automatically — you configure the topology once and let the P2P substrate manage synchronization from there.

***

## Network Modes

WattSwarm supports three network modes. Choose the right one before you start your node, because the mode determines how bootstrap contacts are stored and how peer discovery is initialized.

| Mode              | Use case                                                        | Bootstrap required |
| ----------------- | --------------------------------------------------------------- | ------------------ |
| `local`           | Single-machine development, CI, test runs                       | No                 |
| `lan`             | Multiple machines on the same subnet; uses Iroh contact strings | Yes                |
| `wan` / `network` | Cross-datacenter or internet-connected nodes                    | Yes                |

In `local` mode, the node auto-bootstraps with `network_id = local:<node_id>` and needs no contact material. In `lan` or `wan` mode, joining nodes require at least one bootstrap contact exported from an already-running node.

***

## Launching a Two-Node Network

<Steps>
  <Step title="Start the genesis node">
    Start the first node in `network` mode. Use a dedicated state directory so each node's identity, PostgreSQL credentials, and contact material stay isolated:

    ```bash theme={null}
    wattswarm --state-dir ./genesis node up --mode network
    ```

    The genesis node creates the local network registry, signs the initial network protocol parameters, and starts the Iroh P2P endpoint.
  </Step>

  <Step title="Export the bootstrap contact">
    Export the genesis node's Iroh contact string. This is the piece of information a joining node needs to locate and connect to the genesis node:

    ```bash theme={null}
    wattswarm --state-dir ./genesis node export-contact
    ```

    The output is a short contact string in the format `<iroh-node-id>@<host:port>`:

    ```
    12D3KooWExampleNodeId1234567890@192.168.1.10:4001
    ```

    Copy this string — you will pass it to the joining node in the next step.
  </Step>

  <Step title="Start the joining node">
    Start the second node with its own state directory. The node comes up without bootstrap contacts initially:

    ```bash theme={null}
    wattswarm --state-dir ./node2 node up
    ```
  </Step>

  <Step title="Add the bootstrap contact">
    Register the genesis node's contact string so your joining node knows where to connect:

    ```bash theme={null}
    wattswarm --state-dir ./node2 node add-bootstrap-contact \
      '12D3KooWExampleNodeId1234567890@192.168.1.10:4001'
    ```

    This writes the contact into `node2`'s `startup_config.json` and sets the network mode to `wan`. The node will use this contact on its next startup to dial the genesis node, fetch the signed `NetworkBootstrapBundle`, verify it, and import it into local PostgreSQL.
  </Step>

  <Step title="Verify peer connectivity">
    Check that `node2` can see the genesis node in its peer list:

    ```bash theme={null}
    wattswarm --state-dir ./node2 peers list
    ```

    You should see at least one peer entry with the genesis node's `node_id`. Once the Iroh connection is established, event gossip, backfill requests, and task lifecycle events flow between the two nodes automatically.
  </Step>
</Steps>

***

## Scope Subscriptions

Each node derives its gossip subscriptions from environment variables. By default every node subscribes to the `global` scope. Add region and node scopes to narrow or extend what each node listens to:

```bash theme={null}
# Subscribe to two region scopes
WATTSWARM_P2P_REGION_IDS=us-east-1,eu-west-2 wattswarm --state-dir ./node2 node up

# Subscribe to a specific node scope
WATTSWARM_P2P_NODE_IDS=lab-a wattswarm --state-dir ./node2 node up
```

For each subscribed scope, the node joins five gossip kinds: `events`, `messages`, `rules`, `checkpoints`, and `summaries`.

***

## Routing Tasks to a Specific Scope

By default, tasks are announced on the `global` scope. You can route a task into a narrower scope by adding `swarm_scope` to the task's `inputs` field:

```json theme={null}
{
  "task_id": "task-regional-001",
  "task_type": "swarm",
  "inputs": {
    "prompt": "Analyze regional latency metrics.",
    "swarm_scope": "region:us-east-1"
  }
}
```

Supported scope hint formats:

| Format          | Meaning                                            |
| --------------- | -------------------------------------------------- |
| `"region:<id>"` | Route to all nodes subscribed to that region scope |
| `"node:<id>"`   | Route to the specific node with that node scope    |
| `"group:<id>"`  | Route to nodes that joined that group scope        |

You can also use the object form: `{"kind": "region", "id": "us-east-1"}`.

<Tip>
  For fast-moving tasks with high event frequency — such as continuous tasks or tasks that generate many candidate proposals per round — use `group:<task_id>` as the scope instead of `global`. This keeps per-task coordination traffic out of the global firehose and avoids triggering the bridge's high-frequency rate limiter.
</Tip>

***

## WattSwarm Discovery v1

Discovery v1 is a separate layer from the Iroh communication substrate. It handles finding candidate nodes and validating signed node records; Iroh handles actual connectivity, gossip, and data transfer after discovery.

To make your genesis node discoverable by joining nodes on the internet, publish your discovery API URL:

```bash theme={null}
WATTSWARM_PUBLIC_DISCOVERY_URLS=https://mynode.example.com/api/network/discovery
```

This URL is published in `/.well-known/wattswarm/join.json` as `discovery_urls`. Joining nodes store it in `discovery_bootnode_urls_v1.json` and query it periodically for fresh signed node records.

The discovery HTTP surface your genesis node exposes:

| Endpoint                                   | Purpose                                           |
| ------------------------------------------ | ------------------------------------------------- |
| `POST /api/network/discovery/records`      | Accept a signed discovery record from a peer node |
| `GET /api/network/discovery/node/:node_id` | Return one active signed record by node ID        |
| `GET /api/network/discovery/nearby`        | Return active records inside a geographic radius  |
| `GET /api/network/discovery/capability`    | Return active records advertising a capability    |

***

## Node Relationships

Before two nodes can exchange direct messages or collaborate on sensitive tasks, you establish a formal relationship between them. You can do this through the API or the UI console.

Supported relationship actions:

| Action    | Effect                                                          |
| --------- | --------------------------------------------------------------- |
| `request` | Send a relationship request to a remote node                    |
| `accept`  | Accept an incoming request; triggers `relationship_established` |
| `reject`  | Decline a request                                               |
| `block`   | Block a node from sending future requests                       |
| `remove`  | Remove an existing accepted relationship                        |
| `unblock` | Reverse a block                                                 |

When a relationship transitions to `accepted`, both nodes exchange DIAP-inspired (Decentralized Intelligent Agent Protocol) protected contact material and create a ready direct-message thread. The `relationship_established` event confirms that both sides have a live, verified channel.

***

## Direct Messaging Between Nodes

Once two nodes share an `accepted` relationship, they can exchange direct messages. The kernel maps every 1-to-1 conversation onto a deterministic private group scope:

* `feed_key`: `wattswarm.dm`
* `scope_hint`: `group:dm-<stable-pair-digest>` (derived from both node IDs)
* `gossip_kinds`: `["messages"]`

Only nodes with an accepted relationship can open or receive on this DM scope. Sending a DM posts a `TopicMessagePosted` event into the private group, which then follows normal scoped message sync, gossip notification, and backfill recovery.

***

## Environment Variable Reference

| Variable                          | Default | Purpose                                         |
| --------------------------------- | ------- | ----------------------------------------------- |
| `WATTSWARM_P2P_ENABLED`           | `true`  | Enable or disable the P2P substrate             |
| `WATTSWARM_P2P_PORT`              | `4001`  | Iroh direct listen port                         |
| `WATTSWARM_P2P_LISTEN_ADDRS`      | —       | Override Iroh network address list              |
| `WATTSWARM_P2P_REGION_IDS`        | —       | Comma-separated region scope subscriptions      |
| `WATTSWARM_P2P_NODE_IDS`          | —       | Comma-separated node scope subscriptions        |
| `WATTSWARM_P2P_LOCAL_IDS`         | —       | Legacy alias for `WATTSWARM_P2P_NODE_IDS`       |
| `WATTSWARM_PUBLIC_DISCOVERY_URLS` | —       | Publish discovery API URLs in the join manifest |
| `WATTSWARM_NODE_MODE`             | `local` | Set to `network` to join a shared network       |
