Reliable agent-to-agent communication protocol for transferring large payloads via shared files with pointer references and secret code verification. Trigger...
---
name: agentrelay
description: Reliable agent-to-agent communication protocol for transferring large payloads via shared files with pointer references and secret code verification. Triggered by explicit 'AgentRelay:' prefix in messages.
license: MIT
metadata: {"openclaw":{"triggerPatterns":["AgentRelay:","Please use AgentRelay skill to handle","Use AgentRelay"],"emoji":"📨"}}
---
# AgentRelay 📨
**Reliable Agent-to-Agent Communication Protocol** — Solves `sessions_send` timeout issues for large payloads using shared files + short message pointers.
## 🎯 When to Use This Skill
**When you see messages like the following**, immediately use this Skill to handle:
```
Please use AgentRelay skill to handle this message:
REQ,event_001,s/event_001.json,,
```
Or
```
📨 AgentRelay Protocol Message
Please use AgentRelay skill to handle:
- Message Type: REQ
- Event ID: event_001
- File Pointer: s/event_001.json
```
**Key Trigger Phrases**:
- "use AgentRelay skill to handle"
- "AgentRelay protocol message"
- "Use AgentRelay"
When you see these keywords, **immediately execute the Commands below**!
## 🚀 Quick Start
### Standard Flow After Receiving AgentRelay Message
**Step 1: Parse Message**
```bash
python3 {baseDir}/run_relay.py receive "REQ,event_001,s/event_001.json,,"
```
Example output:
```json
{
"type": "REQ",
"event_id": "event_001",
"content": {
"task": "write_poem",
"sender_agent": "agent:sender:main",
"receiver_agent": "agent:worker:main"
},
"secret": "ABC123"
}
```
**Step 2: Understand Task and Execute**
Check the `content` field to understand what needs to be done (e.g., write poem, analyze data, generate report).
**Step 3: Update Result**
```bash
python3 {baseDir}/run_relay.py complete event_001 "Task completed" "agent:sender:main"
```
**Step 4: Send CMP Confirmation**
```bash
# generate CMP message (done automatically by run_relay.py complete)
# Output: CMP,event_001,,,ABC123
# Then send via sessions_send
sessions_send(target='agent:sender:main', message='CMP,event_001,,,ABC123')
```
---
## 📚 Commands
### `receive <csv_message>`
Parse AgentRelay CSV message and read shared file content.
Accepts either bare CSV or a full message with the `AgentRelay:` prefix.
**Parameters**:
- `csv_message`: CSV format message (without `AgentRelay:` prefix)
**Example**:
```bash
python3 {baseDir}/run_relay.py receive "REQ,event_001,s/event_001.json,,"
```
**Output** (JSON):
```json
{
"type": "REQ",
"event_id": "event_001",
"ptr": "s/event_001.json",
"content": {...},
"secret": "ABC123"
}
```
---
### `update <event_id> <json_updates> [next_event_id]`
Update shared file content.
**Parameters**:
- `event_id`: Event ID
- `json_updates`: JSON format updates (merged into `payload.content`)
**Example**:
```bash
python3 {baseDir}/run_relay.py update event_001 '{"status":"completed","result":"done"}'
```
**Output**:
```json
{"status":"ok","file":"/path/to/event_001.json","ptr":"s/event_001.json"}
```
---
### `cmp <event_id> [secret]`
Generate CMP confirmation message.
**Parameters**:
- `event_id`: Event ID
- `secret`: Secret Code read from file
**Example**:
```bash
python3 {baseDir}/run_relay.py cmp event_001 ABC123
```
**Output**:
```json
{
"status": "ok",
"cmp_message": "CMP,event_001,,,ABC123",
"instruction": "Call sessions_send with message='CMP,event_001,,,ABC123'"
}
```
---
### `verify <cmp_message>`
Verify that a received `CMP` message matches the secret stored in the event file.
**Example**:
```bash
python3 {baseDir}/run_relay.py verify "CMP,event_001,,,ABC123"
```
**Output**:
```json
{
"status": "ok",
"event_id": "event_001",
"verified": true
}
```
---
## 🔄 Complete Communication Flow
### Sender Agent
```python
# 1. Prepare data
content = {
"task": "write_poem",
"sender_agent": "agent:sender:main",
"receiver_agent": "agent:worker:main"
}
# 2. Write to shared file
from agentrelay import agentrelay_send
result = agentrelay_send("agent:worker:main", "REQ", "event_001", content)
# 3. Send message with prefix
message = f"AgentRelay: {result['csv_message']}"
sessions_send(target='agent:worker:main', message=message)
```
### Receiver Agent
```bash
# 1. Receive message: AgentRelay: REQ,event_001,s/event_001.json,,
# 2. Parse message
python3 {baseDir}/run_relay.py receive "REQ,event_001,s/event_001.json,,"
# → Get content and secret
# 3. Understand task, call LLM to execute
# (This is your LLM capability)
# 4. Update result
python3 {baseDir}/run_relay.py update event_001 '{"status":"completed"}'
# 5. Send CMP
CMP_OUTPUT=$(python3 {baseDir}/run_relay.py cmp event_001 SECRET)
CMP_MSG=$(echo "$CMP_OUTPUT" | jq -r '.cmp_message')
sessions_send(target='agent:sender:main', message="$CMP_MSG")
```
---
## 📊 Message Format Details
### CSV Format
```
TYPE,ID,PTR,,DATA
```
**Field Descriptions**:
- `TYPE`: Message type (REQ | CMP)
- `ID`: Event ID (unique identifier)
- `PTR`: File pointer (e.g., `s/event_id.json`)
- `RESERVED`: Reserved field (leave empty)
- `DATA`: Additional data (Secret Code for CMP)
**Examples**:
```
REQ,event_001,s/event_001.json,, # Request
CMP,event_001,,,ABC123 # Completion confirmation
```
### Full Message (with prefix)
```
AgentRelay: REQ,event_001,s/event_001.json,,
```
**Why need prefix?**
- ✅ Clearly identifies this as AgentRelay protocol message
- ✅ LLM immediately knows to call AgentRelay Skill when seeing it
- ✅ Avoids confusion with other messages
---
## 🛡️ Security Mechanisms
### 1. Secret Code Verification
- Sender generates 6-character random code (e.g., `ABC123`)
- Secret is written to file
- Receiver must return the same Secret when sending CMP
- Sender verifies Secret matches, ensuring receiver actually read the file
### 2. Burn-on-read (Optional)
When `burn_on_read=true` is set in `meta` or `payload.content`, the file is automatically deleted after reading to protect sensitive data.
## 📁 Data Storage
- **Shared Files**: `~/.openclaw/data/agentrelay/storage/*.json`
- **Transaction Logs**: `~/.openclaw/data/agentrelay/logs/transactions_*.jsonl`
- **Registry**: `~/.openclaw/data/agentrelay/registry.json`
---
## 🧪 Testing and Examples
### Smoke Test
```bash
python3 {baseDir}/smoke_test.py
```
### Pytest Regression Suite
```bash
pytest {baseDir}/test_agentrelay.py
```
### Cleanup Expired Events
```bash
python3 {baseDir}/cleanup_relay.py
```
### Verify a CMP
```bash
python3 {baseDir}/run_relay.py verify "CMP,r1_r,,,ABC123"
```
---
## ❓ FAQ
### Q: Why use AgentRelay instead of direct sessions_send?
A: `sessions_send` tends to timeout when transmitting messages larger than 30 characters. AgentRelay uses shared files + short pointers (less than 30 characters) to transmit arbitrarily large data.
### Q: What is Secret Code for?
A: Secret Code is a 6-character random code used to verify the receiver actually read the file. Receiver must return the correct Secret in CMP, and sender can verify it with `verify`.
### Q: How long are files retained?
A: Files are retained for 24 hours by default. You can adjust this with `ttl_hours`, enable `burn_on_read` to delete immediately after reading, and run `cleanup_relay.py` to sweep expired files and old registry entries.
---
## 📖 More Documentation
- [README.md](/Users/gavinliu/.openclaw/workspace/skills/agentrelay/README.md) - Project overview
- [RELEASE_NOTES.md](/Users/gavinliu/.openclaw/workspace/skills/agentrelay/RELEASE_NOTES.md) - Release notes
---
**Version**: v1.1.0
**Last Updated**: 2026-02-28
**Author**: AgentRelay Team
**Maintainer**: AgentRelay Team
don't have the plugin yet? install it then click "run inline in claude" again.
restructured into implexa format with explicit decision points for REQ vs CMP message types, added edge cases for network timeouts and file read failures, documented external connections and storage paths, included secret verification logic in decision points and procedure steps, preserved original author attribution.
AgentRelay solves sessions_send timeout issues for payloads larger than 30 characters by using shared files and short pointer references instead of direct message transmission. use this skill when you see explicit "AgentRelay:" prefix in messages or keywords like "use AgentRelay skill to handle" or "AgentRelay protocol message". the skill handles the full roundtrip: parsing incoming requests, executing tasks, writing results back to shared files, and generating completion confirmations with secret code verification.
External Connections:
sessions_send() function: agent-to-agent messaging. no auth required; must be available in runtime context.~/.openclaw/data/agentrelay/storage/*.json directory. must exist and be writable.~/.openclaw/data/agentrelay/logs/transactions_*.jsonl. must exist and be writable.~/.openclaw/data/agentrelay/registry.json. must exist and be writable.Runtime Parameters:
baseDir: path to agentrelay skill directory (contains run_relay.py, smoke_test.py, cleanup_relay.py).csv_message (string): incoming message in CSV format, with or without "AgentRelay:" prefix. format: TYPE,ID,PTR,,DATA.event_id (string): unique event identifier.secret (string): 6-character alphanumeric code for verification.json_updates (JSON object, optional): fields to merge into payload.content.ttl_hours (integer, optional): time-to-live for shared files. default 24 hours.burn_on_read (boolean, optional): if true, delete file immediately after reading.Target Agents:
sender_agent: agent that initiated the request (e.g., "agent:sender:main").receiver_agent: agent that handles the request (e.g., "agent:worker:main").Receive and Parse Message: when you see "AgentRelay:" prefix or trigger keywords, call python3 {baseDir}/run_relay.py receive "<csv_message>" with the raw CSV string (strip the prefix if present). parse the JSON output to extract type, event_id, ptr, content, and secret. halt and report an error if parsing fails or the file pointer is invalid.
Read Shared File: the receive command automatically reads the shared file at the pointer location (e.g., s/event_001.json). the returned JSON includes the full content object with task description, sender/receiver identifiers, and any metadata. if file does not exist or is unreadable, halt and report a file-not-found error.
Understand Task: examine the content.task field (e.g., "write_poem", "analyze_data") and any additional context in content. determine what work needs to be done. if task description is ambiguous or missing, ask for clarification before proceeding.
Execute Task: call the appropriate LLM capability or function to perform the work. this step is context-dependent (write poems, generate reports, transform data, etc.). capture results and any errors.
Update Shared File: call python3 {baseDir}/run_relay.py update event_id '<json_updates>' where json_updates includes at least {"status":"completed"} and any result data. the command merges updates into payload.content and returns the file path and pointer. if update fails (permission denied, disk full), retry once and then report the error.
Generate Completion Message: call python3 {baseDir}/run_relay.py cmp event_id <secret> to produce a CMP (completion) message in the format CMP,event_id,,,<secret>. the output includes the cmp_message string. if secret does not match what was read from file, halt and report a verification failure.
Send Completion Confirmation: call sessions_send(target='<sender_agent>', message='<cmp_message>') to send the CMP back to the originating agent. if sessions_send fails (network timeout, agent unreachable), retry up to 3 times with exponential backoff (1s, 2s, 4s). if all retries fail, log the failure and alert.
Cleanup (Optional): if burn_on_read was enabled, the file is deleted after reading in step 2. if using the default 24-hour TTL, run python3 {baseDir}/cleanup_relay.py periodically (e.g., hourly cron job) to sweep expired files and old registry entries.
receive command.type field is REQ: execute steps 2-7 (full request handling flow).type field is CMP: skip task execution. instead, call python3 {baseDir}/run_relay.py verify "<cmp_message>" to confirm the secret matches. if verified=true, mark event as acknowledged. do not send another CMP.{"status":"error","error_message":"<details>"} and send CMP anyway to acknowledge receipt. include error details in the update.sessions_send times out on first attempt: retry up to 3 times. if all fail, log failure but do not halt (event is already updated in shared file).burn_on_read=true in metadata: the file is deleted after successful receive. any subsequent attempts to read or update will fail; report that file has been burned.for receive command (step 1):
type (REQ or CMP), event_id (string), ptr (string), content (object), secret (string).{"type":"REQ","event_id":"event_001","ptr":"s/event_001.json","content":{"task":"write_poem","sender_agent":"agent:sender:main"},"secret":"ABC123"}.for update command (step 5):
status (ok or error), file (absolute path), ptr (short pointer).{"status":"ok","file":"/home/user/.openclaw/data/agentrelay/storage/event_001.json","ptr":"s/event_001.json"}.for cmp command (step 6):
status (ok or error), cmp_message (CSV string), instruction (human-readable summary).{"status":"ok","cmp_message":"CMP,event_001,,,ABC123","instruction":"Call sessions_send with message='CMP,event_001,,,ABC123'"}.for verify command (decision point, CMP path):
status (ok or error), event_id (string), verified (boolean).{"status":"ok","event_id":"event_001","verified":true}.shared file format (stored in ~/.openclaw/data/agentrelay/storage/event_id.json):
{
"meta": {
"event_id": "event_001",
"type": "REQ",
"sender_agent": "agent:sender:main",
"receiver_agent": "agent:worker:main",
"secret": "ABC123",
"ttl_hours": 24,
"burn_on_read": false,
"created_at": "2026-02-28T12:00:00Z",
"expires_at": "2026-03-01T12:00:00Z"
},
"payload": {
"content": {
"task": "write_poem",
"sender_agent": "agent:sender:main",
"receiver_agent": "agent:worker:main",
"status": "completed",
"result": "..."
}
}
}
transaction log format (appended to ~/.openclaw/data/agentrelay/logs/transactions_YYYY-MM-DD.jsonl):
timestamp, event_id, action (receive, update, cmp, verify), status (ok, error), error_message (if applicable).event_id and correct secret. the CMP can be verified with the verify command.status:"completed" and result data. the transaction log shows an "update" action with status "ok".cleanup_relay.py removes expired files (older than ttl_hours) and old registry entries without errors.verify command returns verified:true for matching secrets and verified:false for mismatches. this proves the receiver actually read the file.receive <csv_message>parse agentrelay CSV message and read shared file content. accepts bare CSV or full message with "AgentRelay:" prefix.
parameters:
csv_message: CSV format message (strip prefix if present).example:
python3 {baseDir}/run_relay.py receive "REQ,event_001,s/event_001.json,,"
output (JSON):
{
"type": "REQ",
"event_id": "event_001",
"ptr": "s/event_001.json",
"content": {"task":"write_poem","sender_agent":"agent:sender:main"},
"secret": "ABC123"
}
edge cases:
status:"error" with message.status:"error" with "file not found".status:"error" with "corrupted payload".burn_on_read=true, file is deleted after reading; subsequent reads fail.update <event_id> <json_updates> [next_event_id]update shared file content. merges json_updates into payload.content.
parameters:
event_id: event ID.json_updates: JSON object (merged into content, e.g., {"status":"completed"}).next_event_id (optional): if provided, create a new event for chaining.example:
python3 {baseDir}/run_relay.py update event_001 '{"status":"completed","result":"poem here"}'
output:
{"status":"ok","file":"/path/to/event_001.json","ptr":"s/event_001.json"}
edge cases:
status:"error" with "unknown event".status:"error" with system error message.json_updates is invalid JSON, return status:"error" with parse error.expires_at), warn but allow update (do not prevent cleanup later).cmp <event_id> [secret]generate CMP confirmation message. verifies secret matches before generating output.
parameters:
event_id: event ID.secret: secret code (optional; if omitted, read from file).example:
python3 {baseDir}/run_relay.py cmp event_001 ABC123
output:
{
"status": "ok",
"cmp_message": "CMP,event_001,,,ABC123",
"instruction": "Call sessions_send with message='CMP,event_001,,,ABC123'"
}
edge cases:
status:"error" with "unknown event".status:"error" with "secret mismatch".status:"error" with "cannot read event file".verify <cmp_message>verify that a received CMP message matches the secret stored in the event file.
parameters:
cmp_message: CSV format CMP message (e.g., CMP,event_001,,,ABC123).example:
python3 {baseDir}/run_relay.py verify "CMP,event_001,,,ABC123"
output:
{
"status": "ok",
"event_id": "event_001",
"verified": true
}
or (on mismatch):
{
"status": "ok",
"event_id": "event_001",
"verified": false
}
edge cases:
status:"error" with parse error.status:"error" with "unknown event".status:"error" with "cannot read event file".# 1. prepare data
content = {
"task": "write_poem",
"sender_agent": "agent:sender:main",
"receiver_agent": "agent:worker:main"
}
# 2. write to shared file (library or script)
from agentrelay import agentrelay_send
result = agentrelay_send("agent:worker:main", "REQ", "event_001", content)
# result['csv_message'] = "REQ,event_001,s/event_001.json,,"
# 3. send message with prefix
message = f"AgentRelay: {result['csv_message']}"
sessions_send(target='agent:worker:main', message=message)
# 1. receive: "AgentRelay: REQ,event_001,s/event_001.json,,"
# 2. parse
python3 {baseDir}/run_relay.py receive "REQ,event_001,s/event_001.json,,"
# output: {"type":"REQ","event_id":"event_001","secret":"ABC123","content":{...}}
# 3. execute task (call LLM, write poem, etc.)
# result: "A rose by any other name..."
# 4. update result
python3 {baseDir}/run_relay.py update event_001 '{"status":"completed","result":"A rose by any other name..."}'
# 5. send CMP
CMP_OUTPUT=$(python3 {baseDir}/run_relay.py cmp event_001 ABC123)
CMP_MSG=$(echo "$CMP_OUTPUT" | jq -r '.cmp_message')
sessions_send(target='agent:sender:main', message="$CMP_MSG")
# 1. receive CMP: "CMP,event_001,,,ABC123"
# 2. verify
python3 {baseDir}/run_relay.py verify "CMP,event_001,,,ABC123"
# output: {"status":"ok","event_id":"event_001","verified":true}
# 3. if verified=true, read shared file to get result
python3 {baseDir}/run_relay.py receive "REQ,event_001,s/event_001.json,,"
# extract result from content.result field
TYPE,ID,PTR,,DATA
field descriptions:
TYPE: message type. "REQ" for request, "CMP" for completion.ID: event ID (unique identifier, alphanumeric).PTR: file pointer (e.g., "s/event_id.json"). short format avoids sessions_send timeouts.RESERVED: reserved field. leave empty.DATA: additional data. for CMP, this is the secret code.examples:
REQ,event_001,s/event_001.json,,
CMP,event_001,,,ABC123
secret code verification: sender generates a 6-character random code (e.g., "ABC123") and writes it to the shared file. receiver must return the same secret when sending CMP. sender verifies with the verify command to ensure receiver actually read the file. this prevents spoofing or eavesdropping.
burn-on-read (optional): if burn_on_read=true is set in file metadata or payload.content, the file is automatically deleted after the first successful read. protects sensitive data from lingering on disk. subsequent reads will fail.
TTL (time-to-live): files expire after ttl_hours (default 24). the cleanup_relay.py script removes expired files and stale registry entries. prevents disk bloat and ensures old events do not pollute the system.
transaction logging: all operations (receive, update, cmp, verify) are logged to ~/.openclaw/data/agentrelay/logs/transactions_*.jsonl with timestamp and status. enables audit trails and debugging.
~/.openclaw/data/agentrelay/storage/*.json. each file is named event_id.json.~/.openclaw/data/agentrelay/logs/transactions_YYYY-MM-DD.jsonl. one file per day, appended.~/.openclaw/data/agentrelay/registry.json. tracks all active and expired events.smoke test:
python3 {baseDir}/smoke_test.py
regression suite:
pytest {baseDir}/test_agentrelay.py
cleanup expired events:
python3 {baseDir}/cleanup_relay.py
verify a CMP manually:
python3 {baseDir}/run_relay.py verify "CMP,event_001,,,ABC123"
Q: why use AgentRelay instead of direct sessions_send?
A: sessions_send times out on payloads larger than about 30 characters. AgentRelay stores large data in shared files and transmits only a short pointer (less than 30 chars), avoiding timeouts and allowing arbitrarily large payloads.
Q: what is secret code for?
A: secret code is a 6-character random code that proves the receiver actually read the shared file. receiver must return the same secret in the CMP. sender verifies with the verify command. prevents spoofing or replay attacks.
Q: how long are files retained?
A: files are retained for 24 hours by default. set ttl_hours in the file metadata to customize. enable burn_on_read to delete immediately after reading. run cleanup_relay.py periodically (e.g., hourly cron) to sweep expired files.
Q: can i send multiple events in parallel?
A: yes. each event has a unique event_id. you can run multiple receive-update-cmp cycles concurrently. the registry and transaction log are designed to handle concurrent access.
Q: what happens if the receiver agent crashes before sending CMP?
A: the shared file is updated with task results (step 5). the sender can still read the results by calling receive again, even if CMP is never sent. the event remains in registry until TTL expires.
Q: can i chain events together?
A: yes. the update command accepts an optional next_event_id parameter. this creates a new event for the next step in a workflow. use this to implement multi-step processes.
version: v1.1.0 last updated: 2026-02-28 original author: agentrelay team maintainer: agentrelay team