@dp-pcs/ogp 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +437 -0
- package/dist/cli/agent-comms.d.ts +55 -0
- package/dist/cli/agent-comms.d.ts.map +1 -0
- package/dist/cli/agent-comms.js +217 -0
- package/dist/cli/agent-comms.js.map +1 -0
- package/dist/cli/expose.d.ts +3 -0
- package/dist/cli/expose.d.ts.map +1 -0
- package/dist/cli/expose.js +104 -0
- package/dist/cli/expose.js.map +1 -0
- package/dist/cli/federation.d.ts +28 -0
- package/dist/cli/federation.d.ts.map +1 -0
- package/dist/cli/federation.js +409 -0
- package/dist/cli/federation.js.map +1 -0
- package/dist/cli/install.d.ts +3 -0
- package/dist/cli/install.d.ts.map +1 -0
- package/dist/cli/install.js +111 -0
- package/dist/cli/install.js.map +1 -0
- package/dist/cli/setup.d.ts +2 -0
- package/dist/cli/setup.d.ts.map +1 -0
- package/dist/cli/setup.js +33 -0
- package/dist/cli/setup.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +305 -0
- package/dist/cli.js.map +1 -0
- package/dist/daemon/agent-comms.d.ts +76 -0
- package/dist/daemon/agent-comms.d.ts.map +1 -0
- package/dist/daemon/agent-comms.js +188 -0
- package/dist/daemon/agent-comms.js.map +1 -0
- package/dist/daemon/doorman.d.ts +52 -0
- package/dist/daemon/doorman.d.ts.map +1 -0
- package/dist/daemon/doorman.js +203 -0
- package/dist/daemon/doorman.js.map +1 -0
- package/dist/daemon/intent-registry.d.ts +11 -0
- package/dist/daemon/intent-registry.d.ts.map +1 -0
- package/dist/daemon/intent-registry.js +101 -0
- package/dist/daemon/intent-registry.js.map +1 -0
- package/dist/daemon/keypair.d.ts +5 -0
- package/dist/daemon/keypair.d.ts.map +1 -0
- package/dist/daemon/keypair.js +25 -0
- package/dist/daemon/keypair.js.map +1 -0
- package/dist/daemon/message-handler.d.ts +20 -0
- package/dist/daemon/message-handler.d.ts.map +1 -0
- package/dist/daemon/message-handler.js +159 -0
- package/dist/daemon/message-handler.js.map +1 -0
- package/dist/daemon/notify.d.ts +7 -0
- package/dist/daemon/notify.d.ts.map +1 -0
- package/dist/daemon/notify.js +54 -0
- package/dist/daemon/notify.js.map +1 -0
- package/dist/daemon/peers.d.ts +66 -0
- package/dist/daemon/peers.d.ts.map +1 -0
- package/dist/daemon/peers.js +171 -0
- package/dist/daemon/peers.js.map +1 -0
- package/dist/daemon/reply-handler.d.ts +67 -0
- package/dist/daemon/reply-handler.d.ts.map +1 -0
- package/dist/daemon/reply-handler.js +176 -0
- package/dist/daemon/reply-handler.js.map +1 -0
- package/dist/daemon/scopes.d.ts +62 -0
- package/dist/daemon/scopes.d.ts.map +1 -0
- package/dist/daemon/scopes.js +113 -0
- package/dist/daemon/scopes.js.map +1 -0
- package/dist/daemon/server.d.ts +8 -0
- package/dist/daemon/server.d.ts.map +1 -0
- package/dist/daemon/server.js +286 -0
- package/dist/daemon/server.js.map +1 -0
- package/dist/shared/config.d.ts +42 -0
- package/dist/shared/config.d.ts.map +1 -0
- package/dist/shared/config.js +42 -0
- package/dist/shared/config.js.map +1 -0
- package/dist/shared/signing.d.ts +13 -0
- package/dist/shared/signing.d.ts.map +1 -0
- package/dist/shared/signing.js +46 -0
- package/dist/shared/signing.js.map +1 -0
- package/docs/agent-comms.md +277 -0
- package/docs/federation-flow.md +407 -0
- package/docs/quickstart.md +241 -0
- package/docs/scopes.md +198 -0
- package/package.json +57 -0
- package/scripts/install-skills.js +32 -0
- package/skills/ogp/SKILL.md +235 -0
- package/skills/ogp-agent-comms/SKILL.md +345 -0
- package/skills/ogp-expose/SKILL.md +281 -0
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
# Agent Communications (v0.2.0)
|
|
2
|
+
|
|
3
|
+
The `agent-comms` intent enables rich agent-to-agent communication with topic routing, priority levels, and reply support.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
Unlike simple `message` intent, `agent-comms` is designed for:
|
|
8
|
+
- **Topic-based routing**: Messages categorized by topic
|
|
9
|
+
- **Priority handling**: Low, normal, or high priority
|
|
10
|
+
- **Conversation threading**: Multi-turn conversations via `conversationId`
|
|
11
|
+
- **Async replies**: Callback or polling mechanisms
|
|
12
|
+
|
|
13
|
+
## Message Schema
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
{
|
|
17
|
+
intent: 'agent-comms',
|
|
18
|
+
from: 'peer-id',
|
|
19
|
+
to: 'your-id',
|
|
20
|
+
nonce: 'unique-id',
|
|
21
|
+
timestamp: 'ISO-8601',
|
|
22
|
+
replyTo?: 'callback-url', // Optional callback for reply
|
|
23
|
+
conversationId?: 'thread-id', // Optional thread identifier
|
|
24
|
+
payload: {
|
|
25
|
+
topic: string, // Required: routing category
|
|
26
|
+
message: string, // Required: message content
|
|
27
|
+
priority?: 'low' | 'normal' | 'high' // Optional: default 'normal'
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## CLI Usage
|
|
33
|
+
|
|
34
|
+
### Send Agent-Comms
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
# Basic message
|
|
38
|
+
ogp federation agent <peer-id> <topic> <message>
|
|
39
|
+
|
|
40
|
+
# With priority
|
|
41
|
+
ogp federation agent stan memory-management "Question" --priority high
|
|
42
|
+
|
|
43
|
+
# With conversation threading
|
|
44
|
+
ogp federation agent stan project-alpha "Follow-up" --conversation conv-123
|
|
45
|
+
|
|
46
|
+
# Wait for reply
|
|
47
|
+
ogp federation agent stan queries "Status?" --wait --timeout 60000
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Examples
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
# Ask about memory management
|
|
54
|
+
ogp federation agent stan memory-management "How do you persist context across sessions?"
|
|
55
|
+
|
|
56
|
+
# High-priority task delegation
|
|
57
|
+
ogp federation agent alice task-delegation "Deploy staging ASAP" --priority high
|
|
58
|
+
|
|
59
|
+
# Query with reply waiting
|
|
60
|
+
ogp federation agent bob queries "What's the current status of project-alpha?" --wait
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Topic Categories
|
|
64
|
+
|
|
65
|
+
Topics are arbitrary strings that you define based on your use case. Common patterns:
|
|
66
|
+
|
|
67
|
+
| Topic | Description |
|
|
68
|
+
|-------|-------------|
|
|
69
|
+
| `memory-management` | Context and memory operations |
|
|
70
|
+
| `task-delegation` | Task assignment and coordination |
|
|
71
|
+
| `project-*` | Project-specific discussions |
|
|
72
|
+
| `queries` | General questions |
|
|
73
|
+
| `status-updates` | Status and progress reports |
|
|
74
|
+
| `planning` | Planning and scheduling |
|
|
75
|
+
|
|
76
|
+
### Topic Restrictions
|
|
77
|
+
|
|
78
|
+
Receiving gateways can restrict which topics a peer can use:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
# Grant Stan only memory and task topics
|
|
82
|
+
ogp federation approve stan \
|
|
83
|
+
--intents agent-comms \
|
|
84
|
+
--topics memory-management,task-delegation
|
|
85
|
+
|
|
86
|
+
# Stan can now send to memory-management ✓
|
|
87
|
+
# Stan cannot send to billing ✗ (403 Topic not allowed)
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Priority Levels
|
|
91
|
+
|
|
92
|
+
| Priority | Behavior |
|
|
93
|
+
|----------|----------|
|
|
94
|
+
| `low` | Background, non-urgent |
|
|
95
|
+
| `normal` | Standard handling (default) |
|
|
96
|
+
| `high` | Expedited, visible indicator |
|
|
97
|
+
|
|
98
|
+
Priority is indicated in notifications:
|
|
99
|
+
```
|
|
100
|
+
[OGP Agent-Comms] [HIGH] Stan → task-delegation: Deploy staging ASAP
|
|
101
|
+
[OGP Agent-Comms] Alice → queries: What's the status?
|
|
102
|
+
[OGP Agent-Comms] [low] Bob → updates: Daily summary attached
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Reply Mechanism
|
|
106
|
+
|
|
107
|
+
### Callback Pattern (Preferred)
|
|
108
|
+
|
|
109
|
+
When you send with `--wait`, your gateway provides a callback URL:
|
|
110
|
+
|
|
111
|
+
```
|
|
112
|
+
replyTo: https://your-gateway.com/federation/reply/nonce-123
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
The receiving gateway can POST a reply to this URL:
|
|
116
|
+
|
|
117
|
+
```json
|
|
118
|
+
{
|
|
119
|
+
"reply": {
|
|
120
|
+
"nonce": "nonce-123",
|
|
121
|
+
"success": true,
|
|
122
|
+
"data": { "answer": "We use PostgreSQL for persistence" },
|
|
123
|
+
"timestamp": "2026-03-23T10:30:00Z"
|
|
124
|
+
},
|
|
125
|
+
"signature": "..."
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Polling Pattern (Fallback)
|
|
130
|
+
|
|
131
|
+
If callback fails or isn't provided, senders can poll:
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
# Sender polls for reply
|
|
135
|
+
GET /federation/reply/nonce-123
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Response:
|
|
139
|
+
```json
|
|
140
|
+
{
|
|
141
|
+
"nonce": "nonce-123",
|
|
142
|
+
"status": "complete",
|
|
143
|
+
"reply": {
|
|
144
|
+
"success": true,
|
|
145
|
+
"data": { "answer": "..." },
|
|
146
|
+
"timestamp": "..."
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Or if not ready:
|
|
152
|
+
```json
|
|
153
|
+
{
|
|
154
|
+
"nonce": "nonce-123",
|
|
155
|
+
"status": "pending",
|
|
156
|
+
"message": "Reply not yet available"
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## Conversation Threading
|
|
161
|
+
|
|
162
|
+
Use `conversationId` for multi-turn conversations:
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
# Start conversation
|
|
166
|
+
ogp federation agent stan project "Let's plan the sprint" --conversation sprint-42
|
|
167
|
+
|
|
168
|
+
# Continue conversation
|
|
169
|
+
ogp federation agent stan project "What about the API changes?" --conversation sprint-42
|
|
170
|
+
|
|
171
|
+
# Both messages share the same thread
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
The receiving gateway sees the `conversationId` in metadata:
|
|
175
|
+
```json
|
|
176
|
+
{
|
|
177
|
+
"ogp": {
|
|
178
|
+
"intent": "agent-comms",
|
|
179
|
+
"topic": "project",
|
|
180
|
+
"message": "What about the API changes?",
|
|
181
|
+
"conversationId": "sprint-42",
|
|
182
|
+
"nonce": "msg-456"
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
## OpenClaw Integration
|
|
188
|
+
|
|
189
|
+
When agent-comms arrives, your OpenClaw agent receives a notification:
|
|
190
|
+
|
|
191
|
+
```
|
|
192
|
+
[OGP Agent-Comms] [HIGH] Stan → memory-management: How do you persist context?
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
Metadata includes full context:
|
|
196
|
+
```json
|
|
197
|
+
{
|
|
198
|
+
"ogp": {
|
|
199
|
+
"from": "stan:18790",
|
|
200
|
+
"intent": "agent-comms",
|
|
201
|
+
"nonce": "abc-123",
|
|
202
|
+
"topic": "memory-management",
|
|
203
|
+
"message": "How do you persist context?",
|
|
204
|
+
"priority": "high",
|
|
205
|
+
"replyTo": "https://stan.example.com/federation/reply/abc-123",
|
|
206
|
+
"conversationId": "conv-001"
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
## Rate Limiting
|
|
212
|
+
|
|
213
|
+
Agent-comms respects per-peer rate limits:
|
|
214
|
+
|
|
215
|
+
```bash
|
|
216
|
+
# Grant 10 messages per minute
|
|
217
|
+
ogp federation approve stan --intents agent-comms --rate 10/60
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
Exceeding the limit returns:
|
|
221
|
+
```
|
|
222
|
+
HTTP 429 Too Many Requests
|
|
223
|
+
Retry-After: 42
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
## Security Best Practices
|
|
227
|
+
|
|
228
|
+
1. **Use topic restrictions**: Grant only necessary topics
|
|
229
|
+
2. **Set appropriate rate limits**: Prevent abuse
|
|
230
|
+
3. **Verify sender context**: Check peer identity in notifications
|
|
231
|
+
4. **Monitor high-priority**: Track high-priority message patterns
|
|
232
|
+
5. **Review conversation threads**: Watch for suspicious threading
|
|
233
|
+
|
|
234
|
+
## Example Flows
|
|
235
|
+
|
|
236
|
+
### One-Shot Question
|
|
237
|
+
|
|
238
|
+
```
|
|
239
|
+
Stan David
|
|
240
|
+
| |
|
|
241
|
+
|--- agent-comms (topic: memory) -->|
|
|
242
|
+
| | Notifies OpenClaw
|
|
243
|
+
| | Agent processes
|
|
244
|
+
|<-- reply (callback) ---------|
|
|
245
|
+
| |
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
### Polling Pattern
|
|
249
|
+
|
|
250
|
+
```
|
|
251
|
+
Stan David
|
|
252
|
+
| |
|
|
253
|
+
|--- agent-comms ------------->|
|
|
254
|
+
| | Stores reply
|
|
255
|
+
|--- GET /reply/:nonce ------->|
|
|
256
|
+
|<-- 404 (not ready) ----------|
|
|
257
|
+
| |
|
|
258
|
+
|--- GET /reply/:nonce ------->|
|
|
259
|
+
|<-- 200 (reply data) ---------|
|
|
260
|
+
| |
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
### Multi-Turn Conversation
|
|
264
|
+
|
|
265
|
+
```
|
|
266
|
+
Stan David
|
|
267
|
+
| |
|
|
268
|
+
|--- agent-comms (conv: c1) -->|
|
|
269
|
+
|<-- ack ----------------------|
|
|
270
|
+
| |
|
|
271
|
+
|--- agent-comms (conv: c1) -->|
|
|
272
|
+
|<-- reply (callback) ---------|
|
|
273
|
+
| |
|
|
274
|
+
|--- agent-comms (conv: c1) -->|
|
|
275
|
+
|<-- reply (callback) ---------|
|
|
276
|
+
| |
|
|
277
|
+
```
|
|
@@ -0,0 +1,407 @@
|
|
|
1
|
+
# Federation Flow
|
|
2
|
+
|
|
3
|
+
Detailed walkthrough of OGP federation message flows.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
1. [Discovery](#discovery)
|
|
8
|
+
2. [Federation Request](#federation-request)
|
|
9
|
+
3. [Federation Approval](#federation-approval)
|
|
10
|
+
4. [Message Exchange](#message-exchange)
|
|
11
|
+
5. [Security Model](#security-model)
|
|
12
|
+
|
|
13
|
+
## Discovery
|
|
14
|
+
|
|
15
|
+
Before federating, peers discover each other via the `/.well-known/ogp` endpoint.
|
|
16
|
+
|
|
17
|
+
### Request
|
|
18
|
+
|
|
19
|
+
```http
|
|
20
|
+
GET /.well-known/ogp HTTP/1.1
|
|
21
|
+
Host: peer.example.com
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### Response
|
|
25
|
+
|
|
26
|
+
```json
|
|
27
|
+
{
|
|
28
|
+
"version": "0.1.0",
|
|
29
|
+
"displayName": "Alice",
|
|
30
|
+
"email": "alice@example.com",
|
|
31
|
+
"gatewayUrl": "https://peer.example.com",
|
|
32
|
+
"publicKey": "302a300506032b6570032100abc123...",
|
|
33
|
+
"endpoints": {
|
|
34
|
+
"request": "https://peer.example.com/federation/request",
|
|
35
|
+
"approve": "https://peer.example.com/federation/approve",
|
|
36
|
+
"reply": "https://peer.example.com/federation/reply/:nonce"
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
This endpoint:
|
|
42
|
+
- Is unauthenticated (public discovery)
|
|
43
|
+
- Returns peer identity and public key
|
|
44
|
+
- Lists federation endpoints
|
|
45
|
+
|
|
46
|
+
## Federation Request
|
|
47
|
+
|
|
48
|
+
Alice wants to federate with Bob. Alice sends a signed request.
|
|
49
|
+
|
|
50
|
+
### Alice's Side
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
ogp federation request https://bob.example.com peer-bob
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
This:
|
|
57
|
+
1. Loads Alice's keypair
|
|
58
|
+
2. Builds peer info with Alice's public key
|
|
59
|
+
3. Signs the peer info with Alice's private key
|
|
60
|
+
4. POSTs to Bob's `/federation/request`
|
|
61
|
+
|
|
62
|
+
### Request
|
|
63
|
+
|
|
64
|
+
```http
|
|
65
|
+
POST /federation/request HTTP/1.1
|
|
66
|
+
Host: bob.example.com
|
|
67
|
+
Content-Type: application/json
|
|
68
|
+
|
|
69
|
+
{
|
|
70
|
+
"peer": {
|
|
71
|
+
"id": "peer-alice",
|
|
72
|
+
"displayName": "Alice",
|
|
73
|
+
"email": "alice@example.com",
|
|
74
|
+
"gatewayUrl": "https://alice.example.com",
|
|
75
|
+
"publicKey": "302a300506032b6570032100def456..."
|
|
76
|
+
},
|
|
77
|
+
"signature": "a1b2c3d4e5f6..."
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Bob's Side
|
|
82
|
+
|
|
83
|
+
Bob's OGP daemon:
|
|
84
|
+
1. Receives request
|
|
85
|
+
2. Stores peer as `pending`
|
|
86
|
+
3. Returns acknowledgment
|
|
87
|
+
|
|
88
|
+
```json
|
|
89
|
+
{
|
|
90
|
+
"received": true,
|
|
91
|
+
"status": "pending",
|
|
92
|
+
"message": "Federation request received and pending approval"
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Bob sees the request:
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
$ ogp federation list --status pending
|
|
100
|
+
|
|
101
|
+
PENDING PEERS:
|
|
102
|
+
|
|
103
|
+
peer-alice
|
|
104
|
+
Name: Alice
|
|
105
|
+
Status: pending
|
|
106
|
+
Gateway: https://alice.example.com
|
|
107
|
+
Public key: 302a300506032b6570032100def456...
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Federation Approval
|
|
111
|
+
|
|
112
|
+
Bob approves Alice's request.
|
|
113
|
+
|
|
114
|
+
### Bob's Side
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
ogp federation approve peer-alice
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
This:
|
|
121
|
+
1. Updates peer status to `approved` in `~/.ogp/peers.json`
|
|
122
|
+
2. POSTs approval to Alice's `/federation/approve`
|
|
123
|
+
|
|
124
|
+
### Request
|
|
125
|
+
|
|
126
|
+
```http
|
|
127
|
+
POST /federation/approve HTTP/1.1
|
|
128
|
+
Host: alice.example.com
|
|
129
|
+
Content-Type: application/json
|
|
130
|
+
|
|
131
|
+
{
|
|
132
|
+
"peerId": "peer-alice",
|
|
133
|
+
"approved": true
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### Alice's Side
|
|
138
|
+
|
|
139
|
+
Alice's OGP daemon:
|
|
140
|
+
1. Receives approval
|
|
141
|
+
2. Updates Bob's status to `approved`
|
|
142
|
+
|
|
143
|
+
Now both sides have approved peers:
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
$ ogp federation list --status approved
|
|
147
|
+
|
|
148
|
+
APPROVED PEERS:
|
|
149
|
+
|
|
150
|
+
peer-bob
|
|
151
|
+
Name: Bob
|
|
152
|
+
Status: approved
|
|
153
|
+
Gateway: https://bob.example.com
|
|
154
|
+
Public key: 302a300506032b6570032100abc123...
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## Message Exchange
|
|
158
|
+
|
|
159
|
+
Alice sends a message to Bob.
|
|
160
|
+
|
|
161
|
+
### Alice Sends
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
ogp federation send peer-bob message '{"text":"Hello, Bob!"}'
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
This:
|
|
168
|
+
1. Builds message object with intent, nonce, timestamp, payload
|
|
169
|
+
2. Signs message with Alice's private key
|
|
170
|
+
3. POSTs to Bob's `/federation/message`
|
|
171
|
+
|
|
172
|
+
### Request
|
|
173
|
+
|
|
174
|
+
```http
|
|
175
|
+
POST /federation/message HTTP/1.1
|
|
176
|
+
Host: bob.example.com
|
|
177
|
+
Content-Type: application/json
|
|
178
|
+
|
|
179
|
+
{
|
|
180
|
+
"message": {
|
|
181
|
+
"intent": "message",
|
|
182
|
+
"from": "peer-alice",
|
|
183
|
+
"to": "peer-bob",
|
|
184
|
+
"nonce": "550e8400-e29b-41d4-a716-446655440000",
|
|
185
|
+
"timestamp": "2026-03-19T10:30:00.000Z",
|
|
186
|
+
"payload": {
|
|
187
|
+
"text": "Hello, Bob!"
|
|
188
|
+
}
|
|
189
|
+
},
|
|
190
|
+
"signature": "a1b2c3d4e5f6..."
|
|
191
|
+
}
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### Bob Receives
|
|
195
|
+
|
|
196
|
+
Bob's OGP daemon:
|
|
197
|
+
1. Verifies sender (`peer-alice`) is in approved peers
|
|
198
|
+
2. Verifies signature using Alice's public key
|
|
199
|
+
3. Checks intent exists in registry
|
|
200
|
+
4. Forwards to Bob's OpenClaw via webhook
|
|
201
|
+
|
|
202
|
+
### OpenClaw Notification
|
|
203
|
+
|
|
204
|
+
```http
|
|
205
|
+
POST /api/system-event HTTP/1.1
|
|
206
|
+
Host: bob-openclaw.local:18789
|
|
207
|
+
Authorization: Bearer bob-token
|
|
208
|
+
Content-Type: application/json
|
|
209
|
+
|
|
210
|
+
{
|
|
211
|
+
"text": "[OGP] Message from Alice: Hello, Bob!",
|
|
212
|
+
"sessionKey": "agent:main:main",
|
|
213
|
+
"ogp": {
|
|
214
|
+
"from": "peer-alice",
|
|
215
|
+
"intent": "message",
|
|
216
|
+
"nonce": "550e8400-e29b-41d4-a716-446655440000",
|
|
217
|
+
"payload": {
|
|
218
|
+
"text": "Hello, Bob!"
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
Bob's OpenClaw agent sees:
|
|
225
|
+
|
|
226
|
+
```
|
|
227
|
+
[OGP] Message from Alice: Hello, Bob!
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
### Response
|
|
231
|
+
|
|
232
|
+
Bob's OGP daemon responds to Alice:
|
|
233
|
+
|
|
234
|
+
```json
|
|
235
|
+
{
|
|
236
|
+
"received": true,
|
|
237
|
+
"timestamp": "2026-03-19T10:30:01.000Z"
|
|
238
|
+
}
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
## Security Model
|
|
242
|
+
|
|
243
|
+
### Keypair Generation
|
|
244
|
+
|
|
245
|
+
Each OGP instance generates an Ed25519 keypair:
|
|
246
|
+
|
|
247
|
+
```typescript
|
|
248
|
+
const { publicKey, privateKey } = crypto.generateKeyPairSync('ed25519');
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
Stored in `~/.ogp/keypair.json`:
|
|
252
|
+
|
|
253
|
+
```json
|
|
254
|
+
{
|
|
255
|
+
"publicKey": "302a300506032b6570032100...",
|
|
256
|
+
"privateKey": "302e020100300506032b657004220420..."
|
|
257
|
+
}
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
### Message Signing
|
|
261
|
+
|
|
262
|
+
When Alice sends a message:
|
|
263
|
+
|
|
264
|
+
1. Build message object
|
|
265
|
+
2. Serialize to JSON
|
|
266
|
+
3. Sign with Ed25519 private key
|
|
267
|
+
|
|
268
|
+
```typescript
|
|
269
|
+
const message = {
|
|
270
|
+
intent: "message",
|
|
271
|
+
from: "peer-alice",
|
|
272
|
+
to: "peer-bob",
|
|
273
|
+
nonce: crypto.randomUUID(),
|
|
274
|
+
timestamp: new Date().toISOString(),
|
|
275
|
+
payload: { text: "Hello!" }
|
|
276
|
+
};
|
|
277
|
+
|
|
278
|
+
const signature = crypto.sign(
|
|
279
|
+
null,
|
|
280
|
+
Buffer.from(JSON.stringify(message)),
|
|
281
|
+
privateKey
|
|
282
|
+
);
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
### Signature Verification
|
|
286
|
+
|
|
287
|
+
When Bob receives a message:
|
|
288
|
+
|
|
289
|
+
1. Look up Alice's public key from `peers.json`
|
|
290
|
+
2. Verify signature
|
|
291
|
+
|
|
292
|
+
```typescript
|
|
293
|
+
const isValid = crypto.verify(
|
|
294
|
+
null,
|
|
295
|
+
Buffer.from(JSON.stringify(message)),
|
|
296
|
+
alicePublicKey,
|
|
297
|
+
signature
|
|
298
|
+
);
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
If signature is invalid:
|
|
302
|
+
- Message is rejected
|
|
303
|
+
- Error returned to sender
|
|
304
|
+
- No notification sent to OpenClaw
|
|
305
|
+
|
|
306
|
+
### Threat Model
|
|
307
|
+
|
|
308
|
+
**OGP protects against:**
|
|
309
|
+
|
|
310
|
+
- ✓ Impersonation (signature verification)
|
|
311
|
+
- ✓ Message tampering (signature covers full message)
|
|
312
|
+
- ✓ Unauthorized peers (approval required)
|
|
313
|
+
- ✓ Man-in-the-middle (HTTPS tunnels)
|
|
314
|
+
|
|
315
|
+
**OGP does NOT protect against:**
|
|
316
|
+
|
|
317
|
+
- ✗ Compromised peer credentials (keep `keypair.json` secure)
|
|
318
|
+
- ✗ DDoS attacks (add rate limiting if needed)
|
|
319
|
+
- ✗ Replay attacks (nonce tracking not yet implemented)
|
|
320
|
+
|
|
321
|
+
### Best Practices
|
|
322
|
+
|
|
323
|
+
1. **Keep private keys secure**
|
|
324
|
+
- Don't commit `~/.ogp/keypair.json` to git
|
|
325
|
+
- Use file permissions: `chmod 600 ~/.ogp/keypair.json`
|
|
326
|
+
|
|
327
|
+
2. **Verify peer identity**
|
|
328
|
+
- Before approving, confirm peer identity out-of-band
|
|
329
|
+
- Check `/.well-known/ogp` matches expected public key
|
|
330
|
+
|
|
331
|
+
3. **Use HTTPS tunnels**
|
|
332
|
+
- Always use cloudflared or ngrok (both provide HTTPS)
|
|
333
|
+
- Never expose raw HTTP to the internet
|
|
334
|
+
|
|
335
|
+
4. **Monitor peer activity**
|
|
336
|
+
- Check OpenClaw logs for suspicious messages
|
|
337
|
+
- Reject peers that send malicious content
|
|
338
|
+
|
|
339
|
+
## Message Flow Diagrams
|
|
340
|
+
|
|
341
|
+
### Full Federation Flow
|
|
342
|
+
|
|
343
|
+
```
|
|
344
|
+
Alice Bob
|
|
345
|
+
| |
|
|
346
|
+
|--- GET /.well-known/ogp -->
|
|
347
|
+
|<-- Discovery response ---|
|
|
348
|
+
| |
|
|
349
|
+
|-- POST /federation/request -->
|
|
350
|
+
|<-- Status: pending -------|
|
|
351
|
+
| |
|
|
352
|
+
| [Bob approves]
|
|
353
|
+
| |
|
|
354
|
+
|<-- POST /federation/approve --
|
|
355
|
+
|--- Acknowledgment --->|
|
|
356
|
+
| |
|
|
357
|
+
|-- POST /federation/message -->
|
|
358
|
+
|<-- Response ----------|
|
|
359
|
+
| |
|
|
360
|
+
| [Bob's OpenClaw]
|
|
361
|
+
| |<-- Webhook
|
|
362
|
+
| |
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
### Message Verification Flow
|
|
366
|
+
|
|
367
|
+
```
|
|
368
|
+
┌─────────────────────────────────────┐
|
|
369
|
+
│ Incoming message + signature │
|
|
370
|
+
└──────────────┬──────────────────────┘
|
|
371
|
+
│
|
|
372
|
+
▼
|
|
373
|
+
┌─────────────────────────────────────┐
|
|
374
|
+
│ 1. Check: Is sender approved? │
|
|
375
|
+
└──────────────┬──────────────────────┘
|
|
376
|
+
│ Yes
|
|
377
|
+
▼
|
|
378
|
+
┌─────────────────────────────────────┐
|
|
379
|
+
│ 2. Load sender's public key │
|
|
380
|
+
└──────────────┬──────────────────────┘
|
|
381
|
+
│
|
|
382
|
+
▼
|
|
383
|
+
┌─────────────────────────────────────┐
|
|
384
|
+
│ 3. Verify signature │
|
|
385
|
+
└──────────────┬──────────────────────┘
|
|
386
|
+
│ Valid
|
|
387
|
+
▼
|
|
388
|
+
┌─────────────────────────────────────┐
|
|
389
|
+
│ 4. Check intent exists │
|
|
390
|
+
└──────────────┬──────────────────────┘
|
|
391
|
+
│ Yes
|
|
392
|
+
▼
|
|
393
|
+
┌─────────────────────────────────────┐
|
|
394
|
+
│ 5. Notify OpenClaw │
|
|
395
|
+
└──────────────┬──────────────────────┘
|
|
396
|
+
│
|
|
397
|
+
▼
|
|
398
|
+
┌─────────────────────────────────────┐
|
|
399
|
+
│ 6. Return success │
|
|
400
|
+
└─────────────────────────────────────┘
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
## Next Steps
|
|
404
|
+
|
|
405
|
+
- See [quickstart.md](./quickstart.md) for hands-on tutorial
|
|
406
|
+
- Check [README.md](../README.md) for CLI reference
|
|
407
|
+
- Explore custom intents in `~/.ogp/intents.json`
|