install
source · Clone the upstream repo
git clone https://github.com/plurigrid/asi
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/plurigrid/asi "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/tailscale-localsend" ~/.claude/skills/plurigrid-asi-tailscale-localsend-30d7cd && rm -rf "$T"
manifest:
skills/tailscale-localsend/SKILL.mdsource content
Tailscale + LocalSend Peer Discovery
Discover peers via Tailscale mesh and exchange files via LocalSend protocol.
Architecture
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐ │ Tailscale API │────▶│ Peer Discovery │────▶│ LocalSend API │ │ (mesh network) │ │ (propagator) │ │ (file xfer) │ └─────────────────┘ └──────────────────┘ └─────────────────┘
Discovery Flow
- Tailscale Status:
→ get mesh peerstailscale status --json - LocalSend Probe: UDP multicast 224.0.0.167:53317 → find localsend-enabled peers
- Intersection: Peers on both networks get deterministic Gay.jl colors
Usage
# Discover peers on tailscale with localsend just ts-localsend-discover # Send file to peer just ts-localsend-send <peer> <file> # Receive mode just ts-localsend-receive
Python API
from tailscale_localsend import TailscaleLocalSend tls = TailscaleLocalSend(seed=0x6761795f636f6c6f) # Discover peers peers = tls.discover() # [{'name': 'macbook', 'tailscale_ip': '100.x.x.x', 'localsend_port': 53317, 'color': '#A855F7'}] # Send file tls.send(peer='macbook', file='data.json') # Receive (blocking) tls.receive(callback=lambda f: print(f"Got {f}"))
Protocol Details
Tailscale Discovery
- Uses
for mesh peerstailscale status --json - Extracts TailscaleIPs for each peer
- Falls back to Tailscale API if CLI unavailable
LocalSend Protocol
- Multicast: 224.0.0.167:53317 (UDP)
- Announce: JSON with alias, fingerprint, port
- Transfer: REST API over HTTPS
POST /api/localsend/v2/prepare-uploadPOST /api/localsend/v2/upload?sessionId=...
Color Assignment
Each peer gets deterministic color from Gay.jl:
peer_color = gay_color_at(hash(peer_fingerprint) % 1000, seed=GAY_SEED)
Integration with epistemic-arbitrage
from epistemic_arbitrage import ArbitrageNetwork network = ArbitrageNetwork(seed=1069) for peer in tls.discover(): network.add_cell(peer['name'], knowledge=peer.get('files', 0)) # Propagate knowledge between peers network.add_propagator(:peer_sync, sources, targets) network.run_parallel(n_workers=len(peers))
Commands
just ts-peers # List tailscale peers just ls-peers # List localsend peers just ts-ls-bridge # Bridge both networks
Base directory: ~/.codex/skills/tailscale-localsend