P2P file transfer between AI agents via message channels.
- 🔗 Message-based: Transfer files through existing chat channels
- 📦 Chunked transfer: Split large files into small pieces
- ✅ Integrity verification: SHA-256 hash for chunks and files
- 🤝 Request/Accept: Explicit acceptance or auto-accept policy
- 🔒 Security: Trusted peer whitelist with secrets
- ⏰ Secret TTL: Set expiry time for trust relationships
- 🔄 Resume: Resume interrupted transfers from last chunk
- 🌐 IPFS Fallback: Auto-upload large files to IPFS
npm install -g ocft# Initialize your node (generates unique ID and secret)
ocft init
# View your status
ocft status
# Export your connection info to share with peers
ocft export
# Add a trusted peer (with optional TTL)
ocft add-peer <nodeId> <secret> --name "Friend" --ttl 24
# Or import from URI
ocft import ocft://eyJub2RlSWQ... --ttl 48| Command | Description |
|---|---|
ocft init |
Initialize node with unique ID and secret |
ocft status |
Show node status and configuration |
ocft show-secret |
Display full secret (careful!) |
ocft export |
Export connection info as URI |
ocft import <uri> |
Import peer from ocft:// URI |
ocft add-peer <id> <secret> |
Add a trusted peer |
ocft remove-peer <id> |
Remove a trusted peer |
ocft list-peers |
List all trusted peers |
ocft set-download <dir> |
Set download directory |
ocft set-max-size <size> |
Set max file size (e.g., 500MB, 2GB) |
ocft set-ttl <hours> |
Set default secret TTL for offers |
ocft extend-peer <id> <hours> |
Extend a peer's trust expiry |
ocft verify <secret> |
Verify if a secret matches yours |
For large files or when the receiver doesn't support OCFT, files can be uploaded to IPFS instead.
| Provider | Description |
|---|---|
pinata |
Pinata Cloud (default) - requires JWT token |
filebase |
Filebase (S3-compatible) - requires access key + secret |
kubo |
Local IPFS node - no auth required |
# Enable IPFS fallback
ocft ipfs-enable
# Set provider
ocft set-ipfs-provider pinata # or: filebase, kubo
# Configure credentials
ocft set-ipfs-key <jwt-token> # Pinata
ocft set-ipfs-key <access-key> --secret <secret> # Filebase
ocft set-kubo-url http://localhost:5001 # Kubo (local node)
# Set size threshold (files larger than this use IPFS)
ocft set-ipfs-threshold 50MB
# Set custom public gateway
ocft set-ipfs-gateway https://ipfs.io/ipfs- If file size > threshold (default 50MB), upload to IPFS
- If receiver doesn't support OCFT, send IPFS link instead
- Receiver downloads from public IPFS gateway
[Sender] [IPFS] [Receiver]
│ │ │
│── Upload (file > 50MB) ───────────>│ │
│<────────────────── CID ────────────│ │
│── Send IPFS link ──────────────────────────────────────────────>│
│ │<── Download from gateway ──│
[Sender] [Receiver]
│ │
│── OFFER ─────────────────>│ (file metadata + secret + TTL)
│<───────────── ACCEPT ─────│ (auto-accept if secret valid & not expired)
│── CHUNK[0] ──────────────>│
│<───────────── ACK[0] ─────│
│── CHUNK[1] ──────────────>│
│<───────────── ACK[1] ─────│
│... │
│── COMPLETE ──────────────>│
│<───────────── ACK ────────│
If a transfer is interrupted, it can be resumed from the last acknowledged chunk:
// Resume a failed transfer
await bot.resumeTransfer(transferId);
// Get list of resumable transfers
const resumable = bot.getResumableTransfers();The receiver sends resumeFrom in the ACCEPT message, and the sender starts from that chunk index.
Set expiry time for trust relationships:
# Add peer with 24-hour trust
ocft add-peer abc123 secret123 --ttl 24
# Set default TTL for all outgoing offers
ocft set-ttl 48
# Extend an existing peer's trust
ocft extend-peer abc123 24Expired secrets are automatically rejected.
When the sender knows the receiver's secret, files are automatically accepted without manual approval:
- Bot A shares their secret with Bot B
- Bot B adds Bot A as trusted peer with the secret
- When Bot B sends a file to Bot A, it includes A's secret
- Bot A verifies the secret (and TTL) and auto-accepts
This enables trusted agent networks to share files seamlessly.
import { TransferManager } from 'ocft';
const bot = new TransferManager({
botId: 'my-bot',
secret: 'my-secret',
secretTTL: 24 * 60 * 60 * 1000, // 24 hours in ms
downloadDir: './downloads',
trustedPeers: [
{ id: 'friend-bot', secret: 'friends-secret', expiresAt: Date.now() + 86400000 }
]
}, async (to, message) => {
await sendMessage(to, message);
});
// Event handlers
bot.on('offer-received', (transfer) => console.log(`Incoming: ${transfer.filename}`));
bot.on('transfer-completed', (transfer) => console.log(`Saved: ${transfer.localPath}`));
// Send a file
await bot.sendFile('friend-bot', '/path/to/file.txt');
// Resume interrupted transfer
await bot.resumeTransfer(transferId);
// Get resumable transfers
const resumable = bot.getResumableTransfers();OCFT messages use a 🔗OCFT: prefix with Base64-encoded JSON:
🔗OCFT:eyJ2ZXJzaW9uIjoiMS4wIiwidHlwZSI6Im9mZmVyIi4uLn0=
This allows file transfers over any text-based channel (Telegram, Discord, Slack, etc).
Config is stored at ~/.ocft/config.json:
{
"nodeId": "ocft_abc123_xyz789",
"secret": "your-secret-key",
"secretTTL": 24,
"trustedPeers": [
{ "id": "peer-id", "secret": "peer-secret", "expiresAt": "2026-02-03T00:00:00Z" }
],
"downloadDir": "~/Downloads/ocft",
"maxFileSize": 1073741824,
"ipfsEnabled": true,
"ipfsProvider": "pinata",
"ipfsThreshold": 52428800,
"ipfsApiKey": "your-pinata-jwt"
}- Chunk size: 48KB (safe for Base64 in messages)
- Default max file size: 100MB (configurable)
- IPFS threshold: 50MB (configurable)
- Designed for text-based channels
MIT