jpskill.com
🛠️ 開発・MCP コミュニティ

p2p-networking

共通の基盤技術を利用して、分散型のGutsネットワークを構築するために、ピアツーピア(P2P)のネットワークパターンを構築・活用するSkill。

📜 元の英語説明(参考)

Peer-to-peer networking patterns using commonware for building decentralized Guts network

🇯🇵 日本人クリエイター向け解説

一言でいうと

共通の基盤技術を利用して、分散型のGutsネットワークを構築するために、ピアツーピア(P2P)のネットワークパターンを構築・活用するSkill。

※ jpskill.com 編集部が日本のビジネス現場向けに補足した解説です。Skill本体の挙動とは独立した参考情報です。

⚡ おすすめ: コマンド1行でインストール(60秒)

下記のコマンドをコピーしてターミナル(Mac/Linux)または PowerShell(Windows)に貼り付けてください。 ダウンロード → 解凍 → 配置まで全自動。

🍎 Mac / 🐧 Linux
mkdir -p ~/.claude/skills && cd ~/.claude/skills && curl -L -o p2p-networking.zip https://jpskill.com/download/8807.zip && unzip -o p2p-networking.zip && rm p2p-networking.zip
🪟 Windows (PowerShell)
$d = "$env:USERPROFILE\.claude\skills"; ni -Force -ItemType Directory $d | Out-Null; iwr https://jpskill.com/download/8807.zip -OutFile "$d\p2p-networking.zip"; Expand-Archive "$d\p2p-networking.zip" -DestinationPath $d -Force; ri "$d\p2p-networking.zip"

完了後、Claude Code を再起動 → 普通に「動画プロンプト作って」のように話しかけるだけで自動発動します。

💾 手動でダウンロードしたい(コマンドが難しい人向け)
  1. 1. 下の青いボタンを押して p2p-networking.zip をダウンロード
  2. 2. ZIPファイルをダブルクリックで解凍 → p2p-networking フォルダができる
  3. 3. そのフォルダを C:\Users\あなたの名前\.claude\skills\(Win)または ~/.claude/skills/(Mac)へ移動
  4. 4. Claude Code を再起動

⚠️ ダウンロード・利用は自己責任でお願いします。当サイトは内容・動作・安全性について責任を負いません。

🎯 このSkillでできること

下記の説明文を読むと、このSkillがあなたに何をしてくれるかが分かります。Claudeにこの分野の依頼をすると、自動で発動します。

📦 インストール方法 (3ステップ)

  1. 1. 上の「ダウンロード」ボタンを押して .skill ファイルを取得
  2. 2. ファイル名の拡張子を .skill から .zip に変えて展開(macは自動展開可)
  3. 3. 展開してできたフォルダを、ホームフォルダの .claude/skills/ に置く
    • · macOS / Linux: ~/.claude/skills/
    • · Windows: %USERPROFILE%\.claude\skills\

Claude Code を再起動すれば完了。「このSkillを使って…」と話しかけなくても、関連する依頼で自動的に呼び出されます。

詳しい使い方ガイドを見る →
最終更新
2026-05-18
取得日時
2026-05-18
同梱ファイル
1

📖 Skill本文(日本語訳)

※ 原文(英語/中国語)を Gemini で日本語化したものです。Claude 自身は原文を読みます。誤訳がある場合は原文をご確認ください。

Guts 用 P2P ネットワーキングスキル

分散型コードコラボレーションプラットフォームのためのピアツーピアネットワーキングを実装します。

Commonware P2P の概要

commonware-p2p クレートは、認証された暗号化されたピア通信を提供します。

ネットワークアーキテクチャ

┌─────────────────────────────────────────────────────────────┐
│                    Guts P2P Network                         │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│   ┌─────────┐     ┌─────────┐     ┌─────────┐              │
│   │ Node A  │────│ Node B  │────│ Node C  │              │
│   └────┬────┘     └────┬────┘     └────┬────┘              │
│        │               │               │                    │
│        └───────────────┼───────────────┘                    │
│                        │                                    │
│                   ┌────┴────┐                               │
│                   │ Node D  │                               │
│                   └─────────┘                               │
│                                                             │
│   Protocol: Noise_XX + Ed25519                              │
│   Transport: QUIC / TCP                                     │
│   Discovery: DHT + Bootstrap nodes                          │
│                                                             │
└─────────────────────────────────────────────────────────────┘

メッセージタイプ

use serde::{Deserialize, Serialize};
use commonware_codec::Codec;

#[derive(Debug, Clone, Serialize, Deserialize, Codec)]
pub enum Message {
    // Handshake
    Hello { version: u32, capabilities: Vec<Capability> },
    HelloAck { version: u32, capabilities: Vec<Capability> },

    // Repository sync
    GetRefs { repository: RepositoryId },
    Refs { repository: RepositoryId, refs: Vec<Ref> },

    GetObjects { repository: RepositoryId, objects: Vec<ObjectId> },
    Objects { repository: RepositoryId, objects: Vec<Object> },

    // Announcements
    NewCommit { repository: RepositoryId, commit: CommitId },
    NewRepository { repository: RepositoryInfo },

    // Gossip
    Gossip { topic: Topic, data: Vec<u8> },

    // Keep-alive
    Ping { nonce: u64 },
    Pong { nonce: u64 },
}

ピア管理

use std::collections::HashMap;
use std::sync::Arc;
use tokio::sync::RwLock;

pub struct PeerManager {
    peers: Arc<RwLock<HashMap<PeerId, PeerState>>>,
    config: PeerConfig,
}

#[derive(Debug)]
pub struct PeerState {
    pub id: PeerId,
    pub address: SocketAddr,
    pub connection: Connection,
    pub last_seen: Instant,
    pub repositories: HashSet<RepositoryId>,
    pub capabilities: Vec<Capability>,
}

impl PeerManager {
    pub async fn connect(&self, addr: SocketAddr) -> Result<PeerId> {
        // Establish encrypted connection
        let connection = Connection::connect(addr, &self.config.keypair).await?;

        // Exchange hello messages
        let peer_info = self.handshake(&connection).await?;

        // Store peer state
        let peer_id = peer_info.id.clone();
        self.peers.write().await.insert(peer_id.clone(), PeerState {
            id: peer_id.clone(),
            address: addr,
            connection,
            last_seen: Instant::now(),
            repositories: HashSet::new(),
            capabilities: peer_info.capabilities,
        });

        Ok(peer_id)
    }

    pub async fn broadcast(&self, message: Message) -> Result<()> {
        let peers = self.peers.read().await;

        let futures: Vec<_> = peers.values()
            .map(|peer| peer.connection.send(message.clone()))
            .collect();

        futures::future::try_join_all(futures).await?;
        Ok(())
    }
}

ゴシッププロトコル

use std::collections::HashSet;

pub struct GossipProtocol {
    seen_messages: HashSet<MessageId>,
    fanout: usize,
    peer_manager: Arc<PeerManager>,
}

impl GossipProtocol {
    pub async fn broadcast(&mut self, topic: Topic, data: Vec<u8>) -> Result<()> {
        let message_id = MessageId::from_content(&topic, &data);

        // Don't rebroadcast
        if !self.seen_messages.insert(message_id.clone()) {
            return Ok(());
        }

        // Select random peers
        let peers = self.peer_manager.random_peers(self.fanout).await;

        // Send to selected peers
        for peer in peers {
            peer.send(Message::Gossip {
                topic: topic.clone(),
                data: data.clone(),
            }).await?;
        }

        Ok(())
    }

    pub async fn handle_gossip(&mut self, peer: PeerId, message: Message) -> Result<()> {
        if let Message::Gossip { topic, data } = message {
            let message_id = MessageId::from_content(&topic, &data);

            // New message, process and rebroadcast
            if self.seen_messages.insert(message_id) {
                self.process_message(topic.clone(), data.clone()).await?;
                self.broadcast(topic, data).await?;
            }
        }
        Ok(())
    }
}

リポジトリ同期

pub struct RepoSync {
    peer_manager: Arc<PeerManager>,
    storage: Arc<Storage>,
}

impl RepoSync {
    pub async fn sync_repository(&self, repo_id: RepositoryId) -> Result<()> {
        // Find peers that have this repository
        let peers = self.peer_manager
            .peers_with_repository(&repo_id)
            .await;

        if peers.is_empty() {
            return Err(SyncError::NoPeers);
        }

        // Get refs from peers
        let local_refs = self.storage.get_refs(&repo_id).await?;

        for peer in peers {
            let remote_refs = self.fetch_refs(&peer, &repo_id).await?;

            // Find missing objects
            let missing = self.diff_refs(&local_refs, &remote_refs);

            if !missing.is_empty() {
                // Fetch missing objects
                let objects = self.fetch_objec
📜 原文 SKILL.md(Claudeが読む英語/中国語)を展開

P2P Networking Skill for Guts

You are implementing peer-to-peer networking for a decentralized code collaboration platform.

Commonware P2P Overview

The commonware-p2p crate provides authenticated, encrypted peer communication.

Network Architecture

┌─────────────────────────────────────────────────────────────┐
│                    Guts P2P Network                         │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│   ┌─────────┐     ┌─────────┐     ┌─────────┐              │
│   │ Node A  │────│ Node B  │────│ Node C  │              │
│   └────┬────┘     └────┬────┘     └────┬────┘              │
│        │               │               │                    │
│        └───────────────┼───────────────┘                    │
│                        │                                    │
│                   ┌────┴────┐                               │
│                   │ Node D  │                               │
│                   └─────────┘                               │
│                                                             │
│   Protocol: Noise_XX + Ed25519                              │
│   Transport: QUIC / TCP                                     │
│   Discovery: DHT + Bootstrap nodes                          │
│                                                             │
└─────────────────────────────────────────────────────────────┘

Message Types

use serde::{Deserialize, Serialize};
use commonware_codec::Codec;

#[derive(Debug, Clone, Serialize, Deserialize, Codec)]
pub enum Message {
    // Handshake
    Hello { version: u32, capabilities: Vec<Capability> },
    HelloAck { version: u32, capabilities: Vec<Capability> },

    // Repository sync
    GetRefs { repository: RepositoryId },
    Refs { repository: RepositoryId, refs: Vec<Ref> },

    GetObjects { repository: RepositoryId, objects: Vec<ObjectId> },
    Objects { repository: RepositoryId, objects: Vec<Object> },

    // Announcements
    NewCommit { repository: RepositoryId, commit: CommitId },
    NewRepository { repository: RepositoryInfo },

    // Gossip
    Gossip { topic: Topic, data: Vec<u8> },

    // Keep-alive
    Ping { nonce: u64 },
    Pong { nonce: u64 },
}

Peer Management

use std::collections::HashMap;
use std::sync::Arc;
use tokio::sync::RwLock;

pub struct PeerManager {
    peers: Arc<RwLock<HashMap<PeerId, PeerState>>>,
    config: PeerConfig,
}

#[derive(Debug)]
pub struct PeerState {
    pub id: PeerId,
    pub address: SocketAddr,
    pub connection: Connection,
    pub last_seen: Instant,
    pub repositories: HashSet<RepositoryId>,
    pub capabilities: Vec<Capability>,
}

impl PeerManager {
    pub async fn connect(&self, addr: SocketAddr) -> Result<PeerId> {
        // Establish encrypted connection
        let connection = Connection::connect(addr, &self.config.keypair).await?;

        // Exchange hello messages
        let peer_info = self.handshake(&connection).await?;

        // Store peer state
        let peer_id = peer_info.id.clone();
        self.peers.write().await.insert(peer_id.clone(), PeerState {
            id: peer_id.clone(),
            address: addr,
            connection,
            last_seen: Instant::now(),
            repositories: HashSet::new(),
            capabilities: peer_info.capabilities,
        });

        Ok(peer_id)
    }

    pub async fn broadcast(&self, message: Message) -> Result<()> {
        let peers = self.peers.read().await;

        let futures: Vec<_> = peers.values()
            .map(|peer| peer.connection.send(message.clone()))
            .collect();

        futures::future::try_join_all(futures).await?;
        Ok(())
    }
}

Gossip Protocol

use std::collections::HashSet;

pub struct GossipProtocol {
    seen_messages: HashSet<MessageId>,
    fanout: usize,
    peer_manager: Arc<PeerManager>,
}

impl GossipProtocol {
    pub async fn broadcast(&mut self, topic: Topic, data: Vec<u8>) -> Result<()> {
        let message_id = MessageId::from_content(&topic, &data);

        // Don't rebroadcast
        if !self.seen_messages.insert(message_id.clone()) {
            return Ok(());
        }

        // Select random peers
        let peers = self.peer_manager.random_peers(self.fanout).await;

        // Send to selected peers
        for peer in peers {
            peer.send(Message::Gossip {
                topic: topic.clone(),
                data: data.clone(),
            }).await?;
        }

        Ok(())
    }

    pub async fn handle_gossip(&mut self, peer: PeerId, message: Message) -> Result<()> {
        if let Message::Gossip { topic, data } = message {
            let message_id = MessageId::from_content(&topic, &data);

            // New message, process and rebroadcast
            if self.seen_messages.insert(message_id) {
                self.process_message(topic.clone(), data.clone()).await?;
                self.broadcast(topic, data).await?;
            }
        }
        Ok(())
    }
}

Repository Synchronization

pub struct RepoSync {
    peer_manager: Arc<PeerManager>,
    storage: Arc<Storage>,
}

impl RepoSync {
    pub async fn sync_repository(&self, repo_id: RepositoryId) -> Result<()> {
        // Find peers that have this repository
        let peers = self.peer_manager
            .peers_with_repository(&repo_id)
            .await;

        if peers.is_empty() {
            return Err(SyncError::NoPeers);
        }

        // Get refs from peers
        let local_refs = self.storage.get_refs(&repo_id).await?;

        for peer in peers {
            let remote_refs = self.fetch_refs(&peer, &repo_id).await?;

            // Find missing objects
            let missing = self.diff_refs(&local_refs, &remote_refs);

            if !missing.is_empty() {
                // Fetch missing objects
                let objects = self.fetch_objects(&peer, &repo_id, missing).await?;

                // Store objects
                for object in objects {
                    self.storage.put_object(&repo_id, object).await?;
                }
            }
        }

        Ok(())
    }
}

Connection Configuration

pub struct NetworkConfig {
    /// Listen address for incoming connections
    pub listen_addr: SocketAddr,

    /// Bootstrap nodes for initial peer discovery
    pub bootstrap_nodes: Vec<SocketAddr>,

    /// Maximum number of concurrent connections
    pub max_connections: usize,

    /// Connection timeout
    pub connection_timeout: Duration,

    /// Keep-alive interval
    pub keepalive_interval: Duration,

    /// Node keypair for authentication
    pub keypair: Ed25519Keypair,
}

impl Default for NetworkConfig {
    fn default() -> Self {
        Self {
            listen_addr: "0.0.0.0:9000".parse().unwrap(),
            bootstrap_nodes: vec![],
            max_connections: 50,
            connection_timeout: Duration::from_secs(10),
            keepalive_interval: Duration::from_secs(30),
            keypair: Ed25519Keypair::generate(),
        }
    }
}

Security Considerations

  1. Authentication: All peers authenticated via Ed25519
  2. Encryption: All traffic encrypted with Noise protocol
  3. Rate Limiting: Limit messages per peer to prevent DoS
  4. Peer Scoring: Track peer behavior, disconnect bad actors
  5. Message Validation: Verify all messages before processing