浏览器

perkoon-transfer

试用

基于 WebRTC 的点对点文件传输,为智能体与人类之间的文件互通设计,无需账号,文件不经过中转服务器。

它能做什么

通过 WebRTC 点对点直连在智能体与人类之间传输文件。提供四种接入方式:MCP Server 适合代码类智能体(Claude Code、Cursor、Windsurf、VS Code Copilot,约 8MB),CLI 适合有 Shell 访问能力的智能体(约 8MB),A2A JSON-RPC 适合仅有 HTTP 能力的智能体(零安装,POST 即可),浏览器自动化适合需要可视验证的场景(约 200MB,含 Chromium)。支持三种传输路径:智能体→人类(分享链接,浏览器直接下载,接收方无需安装任何东西)、智能体→智能体(CLI/MCP/A2A 互连,无人参与)、智能体→管道(直接流式输出到 stdout,不落盘)。输出 JSON 事件流,配合结构化退出码,便于自动化编排。免费、无限制、WebRTC/DTLS 加密传输——文件不经过中转服务器。约束:收发双方必须同时在线。敏感文件建议加 --password 启用密码保护。

什么时候用它

  • 智能体生成报告后通过浏览器链接交给人类用户下载
  • 两个不同运行环境的智能体通过 CLI 或 A2A 互换文件
  • 接收到的文件直接管道到下一个处理流程,不落盘
  • 仅支持 HTTP 的智能体通过 A2A JSON-RPC 端点参与文件传输

技能文档

Perkoon — The Agent Data Layer

File transfer for humans and the things replacing them.

Your agent has compute, memory, and context. What it lacks is a jump gate to the physical world. Perkoon is that gate — P2P file transfer over WebRTC, engineered for autonomous machines from day one.

Not "AI-ready" the way a gas station is gourmet-ready. Actually built for machines — JSON event streams, structured exit codes, MCP native tools, an A2A protocol endpoint, and a state machine that doesn't need a browser, a mouse, or a soul.

Four integration methods — pick the one that fits your runtime:

MethodBest forInstall size
MCP ServerCoding agents (Claude Code, Cursor, Windsurf, VS Code Copilot)~8 MB
CLIAgents with shell access~8 MB
A2A ProtocolAgents with HTTP but no shell (ChatGPT, web agents)Zero — just POST
Browser AutomationFull UI control via Playwright/Puppeteer~200 MB (Chromium)

Three supported flight paths:

  • Agent → Human: Your agent sends a file. The human opens a link in any browser. No install on their end.
  • Agent → Agent: CLI to CLI, MCP to MCP, or A2A to A2A. Two machines, no humans in the loop.
  • Agent → Pipeline: Stream received files to stdout, pipe into processing. No disk writes required.

P2P transfers are free, unlimited, and encrypted. Both ends need to be online — that's the only constraint. For sensitive files, always use --password — without it, anyone with the share link can download.


If your host supports MCP, this is the fastest path. Three native tools, zero shell commands.

Install: npx -y @perkoon/mcp@0.2.2 (stdio transport, pinned version)

Tools provided:

  • send_file — Send a file. Returns session code + share URL. Waits for receiver.
  • receive_file — Receive files from a session code. Saves to disk.
  • check_session — Check if a session is active, expired, or not found.

Configuration for common hosts:

{
  "mcpServers": {
    "perkoon": {
      "command": "npx",
      "args": ["-y", "@perkoon/mcp@0.2.2"]
    }
  }
}
  • Claude Code: Add to .mcp.json in your project
  • Claude Desktop: Add to claude_desktop_config.json
  • Cursor / VS Code / Windsurf: Settings → MCP → Add Server → npx -y @perkoon/mcp@0.2.2

Once configured, just call the tools directly — no bash, no log polling, no background processes.


METHOD 2: CLI (for agents with shell access)

IMPORTANT: Use npx -y perkoon@0.4.6 (pinned version) to avoid dynamic fetching of unaudited code.

SENDING a file

Step 1: Confirm the file path with the user, then start send

Before sending, confirm the file path and name with the user. Do not send files from sensitive directories without explicit user approval.

Replace /path/to/file with the actual file path:

rm -f /tmp/perkoon-send.log /tmp/perkoon-send.pid
npx -y perkoon@0.4.6 send /path/to/file --json --timeout 1800 > /tmp/perkoon-send.log 2>&1 &
echo $! > /tmp/perkoon-send.pid

# Wait for session code (up to 30s)
for i in $(seq 1 30); do
  if grep -q session_created /tmp/perkoon-send.log 2>/dev/null; then
    grep session_created /tmp/perkoon-send.log
    break
  fi
  if grep -q '"event":"error"' /tmp/perkoon-send.log 2>/dev/null; then
    echo "===SEND FAILED===" && cat /tmp/perkoon-send.log
    break
  fi
  sleep 1
done

Output: {"event":"session_created","session_code":"K7MX4QPR9W2N","share_url":"https://perkoon.com/K7MX4QPR9W2N"}

Once session_created appears, share the URL with the user. Example: "Here's your file — open this link on any device to download it: https://perkoon.com/K7MX4QPR9W2N"

The receiver doesn't need to install anything. The link works in any browser.

For password-protected sends, add --password SECRET and share both the URL and password.

Step 2: Monitor until complete — then REPORT BACK

You MUST run this after sharing the link. Do NOT skip this step.

for i in $(seq 1 360); do
  if grep -q transfer_complete /tmp/perkoon-send.log 2>/dev/null; then
    echo "===TRANSFER COMPLETE===" && grep transfer_complete /tmp/perkoon-send.log
    break
  fi
  if grep -q '"event":"error"' /tmp/perkoon-send.log 2>/dev/null; then
    echo "===TRANSFER FAILED===" && grep error /tmp/perkoon-send.log
    break
  fi
  if [ "$((i % 30))" -eq 0 ]; then
    grep progress /tmp/perkoon-send.log 2>/dev/null | tail -1
  fi
  sleep 5
done
  • ===TRANSFER COMPLETE=== → Tell the user: "File sent successfully!" Include speed and duration from the JSON.
  • ===TRANSFER FAILED=== → Tell the user what went wrong.
  • You MUST tell the user the outcome. Never finish silently.

SENDING into a pre-created session (Agent → Agent)

When another agent creates a session via A2A and gives you a session code + sender key:

rm -f /tmp/perkoon-send.log /tmp/perkoon-send.pid
npx -y perkoon@0.4.6 send /path/to/file --session CODE --sender-key KEY --json --timeout 1800 > /tmp/perkoon-send.log 2>&1 &
echo $! > /tmp/perkoon-send.pid

Then monitor with the same Step 2 above. This joins an existing session as sender instead of creating a new one. The receiving agent runs npx -y perkoon@0.4.6 receive CODE --json on their end.

RECEIVING a file

Replace CODE with the 12-character session code:

rm -f /tmp/perkoon-recv.log /tmp/perkoon-recv.pid
npx -y perkoon@0.4.6 receive CODE --json --overwrite --output /home/openclaw/.openclaw/workspace/received/ > /tmp/perkoon-recv.log 2>&1 &
echo $! > /tmp/perkoon-recv.pid

for i in $(seq 1 360); do
  if grep -q transfer_complete /tmp/perkoon-recv.log 2>/dev/null; then
    echo "===TRANSFER COMPLETE===" && grep transfer_complete /tmp/perkoon-recv.log
    break
  fi
  if grep -q '"event":"error"' /tmp/perkoon-recv.log 2>/dev/null; then
    echo "===TRANSFER FAILED===" && grep error /tmp/perkoon-recv.log
    break
  fi
  sleep 5
done

For password-protected sessions, add --password SECRET.

  • ===TRANSFER COMPLETE=== → Tell the user: "File received!" and the save path.
  • ===TRANSFER FAILED=== → Tell the user what went wrong.
  • You MUST tell the user the outcome. Never finish silently.

Files are saved to /home/openclaw/.openclaw/workspace/received/.

Pipe to stdout

Stream a received file directly into another process — no disk write:

npx -y perkoon@0.4.6 receive CODE --output - > /path/to/destination

METHOD 3: A2A Protocol (for agents with HTTP, no shell)

If you can make HTTP requests but can't run shell commands, use the A2A endpoint directly.

Endpoint: POST https://perkoon.com/a2a Protocol: JSON-RPC 2.0 Agent Card: https://perkoon.com/.well-known/agent.json

Discover capabilities

{
  "jsonrpc": "2.0",
  "method": "message/send",
  "id": "1",
  "params": {
    "message": {
      "parts": [{ "type": "data", "data": { "skill": "describe" } }]
    }
  }
}

Create a send session

{
  "jsonrpc": "2.0",
  "method": "message/send",
  "id": "1",
  "params": {
    "message": {
      "parts": [{
        "type": "data",
        "data": {
          "skill": "send-files",
          "name": "quarterly-report"
        }
      }]
    }
  }
}

Returns sender_url (for browser upload) + CLI commands + sender_key for A2A sender joining.

If you have shell access, run the CLI command from the response. If not, share the sender_url with your user — they open it in any browser to upload.

Join a session as receiver

{
  "jsonrpc": "2.0",
  "method": "message/send",
  "id": "1",
  "params": {
    "message": {
      "parts": [{
        "type": "data",
        "data": {
          "skill": "receive-files",
          "session_code": "K7MX4QPR9W2N"
        }
      }]
    }
  }
}

Check session status

{
  "jsonrpc": "2.0",
  "method": "message/send",
  "id": "1",
  "params": {
    "message": {
      "parts": [{
        "type": "data",
        "data": {
          "skill": "session-status",
          "session_code": "K7MX4QPR9W2N"
        }
      }]
    }
  }
}

Runtime hints

Include clientCapabilities in your DataPart to get optimized instructions:

{
  "type": "data",
  "data": {
    "skill": "send-files",
    "clientCapabilities": { "shellAccess": true, "nodeJs": true }
  }
}

Agents declaring shell access get CLI commands. Web-only agents get browser URLs.


METHOD 4: Browser Automation (Playwright/Puppeteer)

For agents that need full browser UI control. Heavier than CLI but gives visual verification.

Ready-to-run scripts (requires npm install playwright):

curl https://perkoon.com/perkoon_send.mjs > send.mjs && node send.mjs /path/to/file.zip
curl https://perkoon.com/perkoon_receive.mjs > receive.mjs && node receive.mjs SESSION_CODE ./output

Manual sender flow

  1. Navigate to https://perkoon.com/create, accept TOS, click Start
  2. Skip confirmation modals: localStorage.setItem('perkoon_skip_confirm_direct-confirm', 'true') and localStorage.setItem('perkoon_skip_confirm_staged-confirm', 'true')
  3. Add files: page.setInputFiles('[data-testid="file-input"]', filePath)
  4. Share session code with recipient
  5. Wait for receiver: page.waitForFunction(() => window.__perkoon?.participants?.length >= 2, null, { timeout: 300000 })
  6. Click [data-testid="send-transfer"]
  7. Wait: page.waitForFunction(() => window.__perkoon?.transfer?.status === 'complete', null, { timeout: 600000 })

Manual receiver flow

  1. Register download handler: page.on('download', d => downloads.push(d))
  2. Navigate to https://perkoon.com/{SESSION_CODE}?agent=true
  3. Accept transfer: wait for [data-testid="transfer-accept"], then click it. This is the RECEIVE-side accept in the "Incoming Transfer" dialog (it appears once the sender's offer arrives) — distinct from the sender's session-creation gate [data-testid="tos-accept"]. Reject is [data-testid="transfer-reject"]. ?agent=true picks the sink but does NOT auto-accept.
  4. Wait: page.waitForFunction(() => window.__perkoon?.transfer?.status === 'complete', null, { timeout: 600000 })
  5. Save: await download.saveAs('./received/' + basename(download.suggestedFilename()))

CLI reference

FlagDescription
--jsonMachine-readable JSON events (always use for automation)
--session Join an existing session as sender (A2A agent-to-agent)
--sender-key Auth key for --session (provided by session creator)
--password Password-protect the session (transfer is WebRTC/DTLS-encrypted regardless)
--timeout Peer wait time (default: 300, use 1800 for sends)
--output Save directory (default: ./received)
--output -Stream to stdout (no disk write)
--overwriteReplace existing files
--quietSuppress human-readable output

JSON event stream

Events appear in order on stdout when using --json. The sequence differs by direction — parse the set that matches the command you ran.

send:

EventMeaningKey fields
file_readyFile queued for sendname, size
session_createdReady — share the link nowsession_code, share_url
waiting_for_receiverSession live, no peer yet
receiver_connectedPeer joined
transfer_acceptedReceiver accepted the transfer
webrtc_connectedDirect P2P link established
progressTransfer in progresspercent, speed, eta
transfer_completeDoneduration_ms, speed

receive:

EventMeaningKey fields
session_joinedJoined the session
sender_foundSender located
webrtc_connectedDirect P2P link established
receiving_fileIncoming filename, size
progressTransfer in progresspercent, speed, eta
transfer_completeDonefiles, duration_ms, speed

Either direction emits error (message, exit_code) on failure.

Exit codes

CodeMeaning
0Success
1Bad arguments
2File not found
3Network/session error
4Wrong password
5Timeout — no peer joined

Rate limits

Session endpoints are rate-limited per IP, sliding 60-second window:

ActionLimit
Create a session (send)10 / min
Join a session (receive)30 / min
Status checks20 / min

Exceeding a limit returns HTTP 429 with a Retry-After value (seconds). On /a2a, every JSON-RPC POST counts against the create budget (10/min), regardless of skill.

How this looks to you: the CLI surfaces a 429 as a fast exit_code: 3 (network/session error) before a session_created event. If a send fails fast with exit 3 after several rapid sessions, treat it as rate-limiting: back off ~30s and retry, don't hammer.


Rules

  1. ALWAYS use --json for parseable output
  2. ALWAYS confirm the file path with the user before sending
  3. Once session_created appears, share the URL with the user
  4. ALWAYS use --timeout 1800 for sends (30 min for the human to open the link)
  5. ALWAYS use --overwrite for receives
  6. ALWAYS monitor until transfer_complete or error — then tell the user the result
  7. NEVER kill the process mid-transfer
  8. The receiver does NOT need perkoon installed — the browser link works for everyone
  9. Use pinned versions: npx -y perkoon@0.4.6 — never use @latest
  10. NEVER send files from sensitive directories (~/.ssh, ~/.gnupg, /etc) without explicit user approval

Discovery endpoints

URLWhat it is
https://perkoon.com/.well-known/agent.jsonA2A agent card (machine-readable capabilities)
https://perkoon.com/llms.txtFull agent integration guide
https://perkoon.com/automateHuman-readable automation docs
https://www.npmjs.com/package/@perkoon/mcpMCP server package
https://www.npmjs.com/package/perkoonCLI package

常见问题

需要注册账号吗?
不需要。会话以 12 位代码标识,双方通过 WebRTC 直接建立连接。
文件会经过官方服务器吗?
不会。传输是 WebRTC/DTLS 端到端加密的,服务器只负责信令协调。
传输对双方有什么要求?
收发双方必须在同一时间在线。发送方会话创建后会等待接收方加入,数据才会真正流动。

相关技能

以 AI 机器人身份加入视频会议,提供语音、虚拟形象与屏幕共享四种模式。

作者 johnpatternai21 次安装8 星标

在本地磁盘以分类纯 Markdown 文件保存需要长期留存的事实,与智能体内置记忆并存。

作者 Iván555 次安装18 星标

通过一次 REST API 调用,向 10 个社交平台发布视频、图片、文字与文档。

作者 victorcavero14375 次安装50 星标

把自然语言描述转为结构化 JSON,并由 mcp-diagram-generator MCP 服务生成 Draw.io、Mermaid 或 Excalidraw 图表文件。

作者 nssa.io1.0k 次安装47 星标

通过一个命令行工具完成多链加密货币交易、钱包管理与 AI 市场分析。

作者 lowesyang162 次安装109 星标