{
  "schemaVersion": "1.0",
  "item": {
    "slug": "cross-comm",
    "name": "Pywayne Cross Comm",
    "source": "tencent",
    "type": "skill",
    "category": "开发工具",
    "sourceUrl": "https://clawhub.ai/wangyendt/cross-comm",
    "canonicalUrl": "https://clawhub.ai/wangyendt/cross-comm",
    "targetPlatform": "OpenClaw"
  },
  "install": {
    "downloadMode": "redirect",
    "downloadUrl": "/downloads/cross-comm",
    "sourceDownloadUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=cross-comm",
    "sourcePlatform": "tencent",
    "targetPlatform": "OpenClaw",
    "installMethod": "Manual import",
    "extraction": "Extract archive",
    "prerequisites": [
      "OpenClaw"
    ],
    "packageFormat": "ZIP package",
    "includedAssets": [
      "SKILL.md"
    ],
    "primaryDoc": "SKILL.md",
    "quickSetup": [
      "Download the package from Yavira.",
      "Extract the archive and review SKILL.md first.",
      "Import or place the package into your OpenClaw setup."
    ],
    "agentAssist": {
      "summary": "Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.",
      "steps": [
        "Download the package from Yavira.",
        "Extract it into a folder your agent can access.",
        "Paste one of the prompts below and point your agent at the extracted folder."
      ],
      "prompts": [
        {
          "label": "New install",
          "body": "I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Tell me what you changed and call out any manual steps you could not complete."
        },
        {
          "label": "Upgrade existing",
          "body": "I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Summarize what changed and any follow-up checks I should run."
        }
      ]
    },
    "sourceHealth": {
      "source": "tencent",
      "status": "healthy",
      "reason": "direct_download_ok",
      "recommendedAction": "download",
      "checkedAt": "2026-04-30T16:55:25.780Z",
      "expiresAt": "2026-05-07T16:55:25.780Z",
      "httpStatus": 200,
      "finalUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=network",
      "contentType": "application/zip",
      "probeMethod": "head",
      "details": {
        "probeUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=network",
        "contentDisposition": "attachment; filename=\"network-1.0.0.zip\"",
        "redirectLocation": null,
        "bodySnippet": null
      },
      "scope": "source",
      "summary": "Source download looks usable.",
      "detail": "Yavira can redirect you to the upstream package for this source.",
      "primaryActionLabel": "Download for OpenClaw",
      "primaryActionHref": "/downloads/cross-comm"
    },
    "validation": {
      "installChecklist": [
        "Use the Yavira download entry.",
        "Review SKILL.md after the package is downloaded.",
        "Confirm the extracted package contains the expected setup assets."
      ],
      "postInstallChecks": [
        "Confirm the extracted package includes the expected docs or setup files.",
        "Validate the skill or prompts are available in your target agent workspace.",
        "Capture any manual follow-up steps the agent could not complete."
      ]
    },
    "downloadPageUrl": "https://openagent3.xyz/downloads/cross-comm",
    "agentPageUrl": "https://openagent3.xyz/skills/cross-comm/agent",
    "manifestUrl": "https://openagent3.xyz/skills/cross-comm/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/cross-comm/agent.md"
  },
  "agentAssist": {
    "summary": "Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.",
    "steps": [
      "Download the package from Yavira.",
      "Extract it into a folder your agent can access.",
      "Paste one of the prompts below and point your agent at the extracted folder."
    ],
    "prompts": [
      {
        "label": "New install",
        "body": "I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Tell me what you changed and call out any manual steps you could not complete."
      },
      {
        "label": "Upgrade existing",
        "body": "I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Summarize what changed and any follow-up checks I should run."
      }
    ]
  },
  "documentation": {
    "source": "clawhub",
    "primaryDoc": "SKILL.md",
    "sections": [
      {
        "title": "Pywayne Cross Comm",
        "body": "pywayne.cross_comm.CrossCommService provides WebSocket-based real-time communication between Python and other languages, with built-in file transfer via Aliyun OSS."
      },
      {
        "title": "Prerequisites",
        "body": "OSS Configuration (required for file/image/folder transfer):\n\nFile transfers use Aliyun OSS. Set these environment variables:\n\n# .env file\nOSS_ENDPOINT=your-oss-endpoint\nOSS_BUCKET_NAME=your-bucket-name\nOSS_ACCESS_KEY_ID=your-access-key\nOSS_ACCESS_KEY_SECRET=your-access-secret\n\nFor more OSS details, see pywayne-aliyun-oss skill."
      },
      {
        "title": "Quick Start",
        "body": "import asyncio\nfrom pywayne.cross_comm import CrossCommService, CommMsgType\n\n# Server\nserver = CrossCommService(role='server', ip='0.0.0.0', port=9898)\nawait server.start_server()\n\n# Client\nclient = CrossCommService(role='client', ip='localhost', port=9898, client_id='my_client')\nawait client.login()"
      },
      {
        "title": "Initialize server",
        "body": "server = CrossCommService(\n    role='server',\n    ip='0.0.0.0',        # Listen on all interfaces\n    port=9898,\n    heartbeat_interval=30,     # Seconds between heartbeats\n    heartbeat_timeout=60       # Seconds before marking offline\n)"
      },
      {
        "title": "Register message listeners",
        "body": "@server.message_listener(msg_type=CommMsgType.TEXT)\nasync def handle_text(message):\n    print(f\"From {message.from_client_id}: {message.content}\")\n\n@server.message_listener(msg_type=CommMsgType.FILE, download_directory=\"./downloads\")\nasync def handle_file(message):\n    print(f\"File downloaded: {message.content}\")"
      },
      {
        "title": "Start server",
        "body": "await server.start_server()  # Blocks until server stops"
      },
      {
        "title": "Get online clients",
        "body": "online_clients = server.get_online_clients()  # Returns list of client IDs"
      },
      {
        "title": "Initialize client",
        "body": "client = CrossCommService(\n    role='client',\n    ip='localhost',           # Server address\n    port=9898,\n    client_id='my_client',    # Optional: auto-generated if omitted\n    heartbeat_interval=30,\n    heartbeat_timeout=60\n)"
      },
      {
        "title": "Login and logout",
        "body": "success = await client.login()\nif success:\n    print(\"Connected!\")\n    # ... communicate ...\n    await client.logout()"
      },
      {
        "title": "Send messages",
        "body": "# Broadcast to all\nawait client.send_message(\"Hello!\", CommMsgType.TEXT)\n\n# Send to specific client\nawait client.send_message(\"Private\", CommMsgType.TEXT, to_client_id='target_id')\n\n# JSON message\nawait client.send_message('{\"key\": \"value\"}', CommMsgType.JSON)\n\n# Dict message\nawait client.send_message({\"type\": \"data\", \"value\": 123}, CommMsgType.DICT)\n\n# Bytes (auto base64 encoded)\nawait client.send_message(b\"binary\", CommMsgType.BYTES)\n\n# File (auto uploads to OSS)\nawait client.send_message(\"/path/to/file.txt\", CommMsgType.FILE)\n\n# Image (auto uploads to OSS)\nawait client.send_message(\"/path/to/image.jpg\", CommMsgType.IMAGE)\n\n# Folder (auto uploads to OSS)\nawait client.send_message(\"/path/to/folder\", CommMsgType.FOLDER)"
      },
      {
        "title": "Get client list",
        "body": "# All clients (online + offline)\nall_clients = await client.list_clients(only_show_online=False)\n# Returns: {'clients': [...], 'total_count': N, 'only_show_online': False}\n\n# Online only\nonline = await client.list_clients(only_show_online=True)"
      },
      {
        "title": "Message Types",
        "body": "CommMsgType enum (use these, not strings):\n\nTypeDescriptionCommMsgType.TEXTPlain textCommMsgType.JSONJSON stringCommMsgType.DICTPython dictCommMsgType.BYTESBinary dataCommMsgType.IMAGEImage fileCommMsgType.FILERegular fileCommMsgType.FOLDERFolder\n\nInternal types (auto-handled): HEARTBEAT, LOGIN, LOGOUT, LIST_CLIENTS, LIST_CLIENTS_RESPONSE, LOGIN_RESPONSE"
      },
      {
        "title": "Message Listener Decorator",
        "body": "# Listen to specific type\n@service.message_listener(msg_type=CommMsgType.TEXT)\nasync def handler(message):\n    pass\n\n# Listen from specific sender\n@service.message_listener(msg_type=CommMsgType.FILE, from_client_id='specific_client')\nasync def handler(message):\n    pass\n\n# Listen to all types\n@service.message_listener()\nasync def handler(message):\n    pass\n\nNote: Listeners automatically filter out messages sent by yourself."
      },
      {
        "title": "File Download Control",
        "body": "File downloads are controlled via the listener's download_directory parameter:\n\n# Auto-download files to ./downloads\n@client.message_listener(msg_type=CommMsgType.FILE, download_directory=\"./downloads\")\nasync def handle_file(message):\n    # message.content contains downloaded file path\n    print(f\"Downloaded: {message.content}\")\n\n# No auto-download - saves bandwidth\n@client.message_listener(msg_type=CommMsgType.FILE, from_client_id='low_priority')\nasync def handle_file(message):\n    # message.content contains OSS key, not downloaded\n    print(f\"File available: {message.oss_key}\")\n    # Optionally: client.download_file_manually(message.oss_key, \"./manual_downloads/\")"
      },
      {
        "title": "Manual download",
        "body": "success = client.download_file_manually(\n    oss_key=\"cross_comm/sender_id/123456_file.txt\",\n    save_directory=\"./downloads\"\n)"
      },
      {
        "title": "Message Object",
        "body": "@dataclass\nclass Message:\n    msg_id: str                    # Unique message ID\n    from_client_id: str            # Sender ID\n    to_client_id: str              # 'all' or specific client ID\n    msg_type: CommMsgType           # Message type enum\n    content: Any                   # Message content\n    timestamp: float                # Unix timestamp\n    oss_key: Optional[str]         # OSS key for file transfers\n\n    def to_dict(self) -> Dict:      # Convert to dict\n    @classmethod\n    def from_dict(cls, data) -> 'Message':  # Create from dict"
      },
      {
        "title": "Client ID Generation",
        "body": "If client_id is not specified, it's auto-generated using MAC address + UUID:\n\nFormat: {mac_address}_{uuid_suffix}\nExample: a1b2c3d4e5f6_abc12345"
      },
      {
        "title": "Command Line",
        "body": "# Run server\npython -m pywayne.cross_comm server\n\n# Run client\npython -m pywayne.cross_comm client"
      },
      {
        "title": "Important Notes",
        "body": "File transfer: Requires OSS environment variables; files auto-upload on send\nAsync required: All operations are async; use asyncio.run() or await in async context\nHeartbeat: Auto-managed; adjust intervals for network conditions\nMessage filtering: Use download_directory to control auto-downloads and save bandwidth\nState persistence: Server saves client status to cross_comm_clients.yaml\nRole-specific methods: Server has start_server(), get_online_clients(); client has login(), logout(), send_message(), list_clients()"
      }
    ],
    "body": "Pywayne Cross Comm\n\npywayne.cross_comm.CrossCommService provides WebSocket-based real-time communication between Python and other languages, with built-in file transfer via Aliyun OSS.\n\nPrerequisites\n\nOSS Configuration (required for file/image/folder transfer):\n\nFile transfers use Aliyun OSS. Set these environment variables:\n\n# .env file\nOSS_ENDPOINT=your-oss-endpoint\nOSS_BUCKET_NAME=your-bucket-name\nOSS_ACCESS_KEY_ID=your-access-key\nOSS_ACCESS_KEY_SECRET=your-access-secret\n\n\nFor more OSS details, see pywayne-aliyun-oss skill.\n\nQuick Start\nimport asyncio\nfrom pywayne.cross_comm import CrossCommService, CommMsgType\n\n# Server\nserver = CrossCommService(role='server', ip='0.0.0.0', port=9898)\nawait server.start_server()\n\n# Client\nclient = CrossCommService(role='client', ip='localhost', port=9898, client_id='my_client')\nawait client.login()\n\nServer\nInitialize server\nserver = CrossCommService(\n    role='server',\n    ip='0.0.0.0',        # Listen on all interfaces\n    port=9898,\n    heartbeat_interval=30,     # Seconds between heartbeats\n    heartbeat_timeout=60       # Seconds before marking offline\n)\n\nRegister message listeners\n@server.message_listener(msg_type=CommMsgType.TEXT)\nasync def handle_text(message):\n    print(f\"From {message.from_client_id}: {message.content}\")\n\n@server.message_listener(msg_type=CommMsgType.FILE, download_directory=\"./downloads\")\nasync def handle_file(message):\n    print(f\"File downloaded: {message.content}\")\n\nStart server\nawait server.start_server()  # Blocks until server stops\n\nGet online clients\nonline_clients = server.get_online_clients()  # Returns list of client IDs\n\nClient\nInitialize client\nclient = CrossCommService(\n    role='client',\n    ip='localhost',           # Server address\n    port=9898,\n    client_id='my_client',    # Optional: auto-generated if omitted\n    heartbeat_interval=30,\n    heartbeat_timeout=60\n)\n\nLogin and logout\nsuccess = await client.login()\nif success:\n    print(\"Connected!\")\n    # ... communicate ...\n    await client.logout()\n\nSend messages\n# Broadcast to all\nawait client.send_message(\"Hello!\", CommMsgType.TEXT)\n\n# Send to specific client\nawait client.send_message(\"Private\", CommMsgType.TEXT, to_client_id='target_id')\n\n# JSON message\nawait client.send_message('{\"key\": \"value\"}', CommMsgType.JSON)\n\n# Dict message\nawait client.send_message({\"type\": \"data\", \"value\": 123}, CommMsgType.DICT)\n\n# Bytes (auto base64 encoded)\nawait client.send_message(b\"binary\", CommMsgType.BYTES)\n\n# File (auto uploads to OSS)\nawait client.send_message(\"/path/to/file.txt\", CommMsgType.FILE)\n\n# Image (auto uploads to OSS)\nawait client.send_message(\"/path/to/image.jpg\", CommMsgType.IMAGE)\n\n# Folder (auto uploads to OSS)\nawait client.send_message(\"/path/to/folder\", CommMsgType.FOLDER)\n\nGet client list\n# All clients (online + offline)\nall_clients = await client.list_clients(only_show_online=False)\n# Returns: {'clients': [...], 'total_count': N, 'only_show_online': False}\n\n# Online only\nonline = await client.list_clients(only_show_online=True)\n\nMessage Types\n\nCommMsgType enum (use these, not strings):\n\nType\tDescription\nCommMsgType.TEXT\tPlain text\nCommMsgType.JSON\tJSON string\nCommMsgType.DICT\tPython dict\nCommMsgType.BYTES\tBinary data\nCommMsgType.IMAGE\tImage file\nCommMsgType.FILE\tRegular file\nCommMsgType.FOLDER\tFolder\n\nInternal types (auto-handled): HEARTBEAT, LOGIN, LOGOUT, LIST_CLIENTS, LIST_CLIENTS_RESPONSE, LOGIN_RESPONSE\n\nMessage Listener Decorator\n# Listen to specific type\n@service.message_listener(msg_type=CommMsgType.TEXT)\nasync def handler(message):\n    pass\n\n# Listen from specific sender\n@service.message_listener(msg_type=CommMsgType.FILE, from_client_id='specific_client')\nasync def handler(message):\n    pass\n\n# Listen to all types\n@service.message_listener()\nasync def handler(message):\n    pass\n\n\nNote: Listeners automatically filter out messages sent by yourself.\n\nFile Download Control\n\nFile downloads are controlled via the listener's download_directory parameter:\n\n# Auto-download files to ./downloads\n@client.message_listener(msg_type=CommMsgType.FILE, download_directory=\"./downloads\")\nasync def handle_file(message):\n    # message.content contains downloaded file path\n    print(f\"Downloaded: {message.content}\")\n\n# No auto-download - saves bandwidth\n@client.message_listener(msg_type=CommMsgType.FILE, from_client_id='low_priority')\nasync def handle_file(message):\n    # message.content contains OSS key, not downloaded\n    print(f\"File available: {message.oss_key}\")\n    # Optionally: client.download_file_manually(message.oss_key, \"./manual_downloads/\")\n\nManual download\nsuccess = client.download_file_manually(\n    oss_key=\"cross_comm/sender_id/123456_file.txt\",\n    save_directory=\"./downloads\"\n)\n\nMessage Object\n@dataclass\nclass Message:\n    msg_id: str                    # Unique message ID\n    from_client_id: str            # Sender ID\n    to_client_id: str              # 'all' or specific client ID\n    msg_type: CommMsgType           # Message type enum\n    content: Any                   # Message content\n    timestamp: float                # Unix timestamp\n    oss_key: Optional[str]         # OSS key for file transfers\n\n    def to_dict(self) -> Dict:      # Convert to dict\n    @classmethod\n    def from_dict(cls, data) -> 'Message':  # Create from dict\n\nClient ID Generation\n\nIf client_id is not specified, it's auto-generated using MAC address + UUID:\n\nFormat: {mac_address}_{uuid_suffix}\nExample: a1b2c3d4e5f6_abc12345\nCommand Line\n# Run server\npython -m pywayne.cross_comm server\n\n# Run client\npython -m pywayne.cross_comm client\n\nImportant Notes\nFile transfer: Requires OSS environment variables; files auto-upload on send\nAsync required: All operations are async; use asyncio.run() or await in async context\nHeartbeat: Auto-managed; adjust intervals for network conditions\nMessage filtering: Use download_directory to control auto-downloads and save bandwidth\nState persistence: Server saves client status to cross_comm_clients.yaml\nRole-specific methods: Server has start_server(), get_online_clients(); client has login(), logout(), send_message(), list_clients()"
  },
  "trust": {
    "sourceLabel": "tencent",
    "provenanceUrl": "https://clawhub.ai/wangyendt/cross-comm",
    "publisherUrl": "https://clawhub.ai/wangyendt/cross-comm",
    "owner": "wangyendt",
    "version": "0.1.0",
    "license": null,
    "verificationStatus": "Indexed source record"
  },
  "links": {
    "detailUrl": "https://openagent3.xyz/skills/cross-comm",
    "downloadUrl": "https://openagent3.xyz/downloads/cross-comm",
    "agentUrl": "https://openagent3.xyz/skills/cross-comm/agent",
    "manifestUrl": "https://openagent3.xyz/skills/cross-comm/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/cross-comm/agent.md"
  }
}