Skip to content

Transport Reference

Technical specifications for Kunuleco transport layers.


Transport Priority

There is no single priority list. The node uses one order to make first contact and another to send over connections that already exist. Checked against the source on 2026-09-30. Paths are under src/kunuleco/.

First contact (join)

Each arm counts only when the peer's signed hello verifies and the host answers the join. A connection with no verified hello, or a host that stays silent, moves the walk to the next arm. transport disable <t> skips an arm, and transport force <t> skips every other arm and the race.

join form Order Source
join <name#TAG> [presence] 1. an existing LAN (mDNS) session · 2. Veilid · 3. Tor · 4. IPFS · 5. a race of every endpoint in the peer's record at once, first to connect wins (skipped when an earlier arm reached the host and the host stayed silent) verbs/invite_system.py:1541, :1608, :1659, :1711, :1751
join <short-code> 1. an existing LAN session · 2. Veilid · 3. Tor · 4. IPFS. No race verbs/invite_system.py:1873, :1888, :1936, :1987
join <kunul1… seed> a race of the LAN addresses in the seed verbs/unified_verbs.py:13495

The race starts every endpoint in the same pass (transport/connection_racer.py:129). The endpoint priorities (private LAN address 1, Veilid 2, Tor 3, IPFS 4, public address 5) set the order the attempts start in, not a wait between them, so the first endpoint to connect wins whatever its priority.

Sending over an existing connection

No send path opens a new connection.

What is sent Order Source
tell / whisper, and the outbox flush 1. the LAN (mDNS) session · 2. any other live CapTP session to that peer · 3. Tor · 4. Veilid · 5. the invite system's lookup, which checks LAN, Tor, Veilid, then IPFS. If the peer has no connected session, the message is queued in the outbox first verbs/unified_verbs.py:3936, :3949, :3963, :3975, :3988; verbs/invite_system.py:1170; queueing at verbs/unified_verbs.py:229
Speech in a presence, to remote members 1. the LAN session · 2. the member's stored connection · 3. Tor · 4. Veilid. Tor leads Veilid because a Veilid route can accept a message and lose it captp/message_router.py:2180, :2191, :2204, :2217; the reason at :2124
Other presence traffic (send_to_peer) 1. any live CapTP session · 2. Tor · 3. Veilid captp/message_router.py:2531, :2567, :2578

P2PCapTPBridge.send_via_best_transport (transport/veilid/bridge.py:4637, TCP, then Veilid, then IPFS) is attached to the bridge but nothing calls it.


mDNS Transport

Service Definition

Property Value
Service Type _kunuleco._tcp.local.
Port 4243 (the CapTP port, set by KUNULECO_CAPTP_PORT)
Protocol TCP

Service TXT Records

All four keys are unsigned hints. The signed CapTP hello decides who the peer is.

Key Value
identity Name#Discriminator
version 0.5.0
captp_port The CapTP port to dial (4243 by default)
verify_key Hex-encoded Ed25519 verify key (omitted when the identity has none)

Simultaneous Dials

Two peers that discover each other may both dial at once. The CapTP layer merges the two connections into one session.

Reconnection

  • At most 8 LAN dials in flight
  • Backoff after a failed dial: 10 s, doubling to 300 s

Veilid Transport

API Connection

Property Value
Host localhost
Port 15959 on an installed node, 5959 without a config file (see Configuration)
Protocol JSON over HTTP

Route Configuration

Setting Value
Refresh interval 120 seconds (transport/veilid/__init__.py:27)
Stability Reliable
Sequencing EnsureOrdered
Hop count Default

Route Blob Format

Opaque binary blob (base64-encoded for transmission).

Message Operations

Operation Latency
app_message (fire-and-forget) 5-10ms
app_call (round-trip) ~183ms through CGNAT
Route import 4-10ms

Status Response

{
  "available": true,
  "running": true,
  "route_id": "...",
  "peer_count": 5
}

Tor Transport

Configuration

Property Value
SOCKS Port 19050 (isolated) or 9050 (system)
Control Port 19051 (isolated) or 9051 (system)
CapTP Port 4243

Onion Service

Property Value
Version 3 (v3 onion addresses)
Port 80 (mapped to local 4243)
Persistence Persistent (key stored)

Key Storage

<data_dir>/tor_data/
└── onion_private_key

Authentication

Methods (in order of preference):

  1. Cookie authentication
  2. Password (via TOR_CONTROL_PASSWORD)
  3. No authentication (if enabled in torrc)

Status Response

{
  "available": true,
  "running": true,
  "onion_address": "abc123...xyz.onion",
  "peer_count": 2
}

IPFS Transport

API Connection

Property Value
Host localhost
Port 15001 (isolated) or 5001 (system)
Protocol HTTP

Required Configuration

Pubsub.Router = "gossipsub"
Experimental.Libp2pStreamMounting = true

P2P Protocol

Property Value
Protocol /x/kunuleco/1.0.0
Legacy /x/kunuleco (cleaned on startup)

Discovery PubSub

Property Value
Topic kunuleco:discovery
Message Format JSON

Discovery Message

{
  "type": "presence",
  "peer_id": "QmYourPeerID...",
  "identity": "Name#1234",
  "timestamp": 1706640000
}

Connection Strategies

  1. Direct IP — If peer IP is known
  2. DHT Routing — Use IPFS DHT to find addresses
  3. Circuit Relay — NAT traversal via relay nodes

Port Summary

Default Configuration

Service Standard Kunuleco Isolated
IPFS API 5001 15001
IPFS Swarm 4001 14001
IPFS Gateway 8080 18080
Veilid API 5959 5959
Tor SOCKS 9050 19050
Tor Control 9051 19051
Kunuleco CapTP 4243 4243

Wire Protocol

All transports ultimately carry CapTP messages.

Framing

Messages are length-prefixed:

┌──────────────┬────────────────────────────┐
│ 4-byte len   │ JSON payload               │
│ (big-endian) │                            │
└──────────────┴────────────────────────────┘

Health Check Endpoints

mDNS

No endpoint — health determined by service registration.

Veilid

GET http://localhost:5959/

IPFS

GET http://localhost:15001/api/v0/id

Tor

Control port connection with AUTHENTICATE command.