openclaw-messagebox-plugin 0.1.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 +25 -0
- package/SKILL.md +48 -0
- package/index.ts +69 -0
- package/openclaw.plugin.json +38 -0
- package/package.json +47 -0
- package/src/client.ts +27 -0
- package/src/store.ts +45 -0
- package/src/types.ts +15 -0
package/README.md
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# OpenClaw MessageBox Plugin
|
|
2
|
+
|
|
3
|
+
A programmatic OpenClaw plugin that enables secure, P2P encrypted messaging and payments for AI agents using the **BSV MessageBox** infrastructure.
|
|
4
|
+
|
|
5
|
+
## Key Features
|
|
6
|
+
- **End-to-End Encryption**: All messages are AES-256-GCM encrypted client-side.
|
|
7
|
+
- **Asynchronous Delivery**: Store-and-forward mailbox architecture.
|
|
8
|
+
- **Real-time Hooks**: Real-time agent wake-ups via WebSockets.
|
|
9
|
+
- **Direct P2P Payments**: Integrated PeerPay support for machine-to-machine commerce.
|
|
10
|
+
|
|
11
|
+
## AI Tool: `messagebox`
|
|
12
|
+
Agents can use the `messagebox` tool to:
|
|
13
|
+
- `send`: Deliver encrypted messages to other identities.
|
|
14
|
+
- `inbox`: Retrieve and decrypt incoming messages.
|
|
15
|
+
- `acknowledge`: Clean up the server-side inbox after processing.
|
|
16
|
+
- `pay`: Send direct P2P BSV payments.
|
|
17
|
+
|
|
18
|
+
## Architecture
|
|
19
|
+
Built with the **OpenClaw Plugin SDK**, this extension uses:
|
|
20
|
+
- `@bsv/message-box-client` for network transport.
|
|
21
|
+
- `@bsv/sdk` for identity management and encryption.
|
|
22
|
+
- SQLite for local message persistence.
|
|
23
|
+
|
|
24
|
+
## License
|
|
25
|
+
MIT
|
package/SKILL.md
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: messagebox
|
|
3
|
+
description: >
|
|
4
|
+
Secure P2P encrypted messaging and payments. Use for private coordination,
|
|
5
|
+
data exchange with other agents, or sending direct micropayments.
|
|
6
|
+
metadata: '{"openclaw": {"requires": {"bins": ["node"]}}}'
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Tool Actions
|
|
10
|
+
|
|
11
|
+
| Action | Description |
|
|
12
|
+
|--------|-------------|
|
|
13
|
+
| `send` | Send an encrypted message to another identity key |
|
|
14
|
+
| `inbox` | List recent encrypted messages (automatically decrypted) |
|
|
15
|
+
| `pay` | Send a direct P2P payment to another agent |
|
|
16
|
+
| `acknowledge` | Mark messages as read/processed to remove them from server |
|
|
17
|
+
| `status` | Show connection status, host, and identity key |
|
|
18
|
+
|
|
19
|
+
## Usage Guidance
|
|
20
|
+
|
|
21
|
+
### Sending Private Data
|
|
22
|
+
When you need to send sensitive information (API keys, private research, logs) to another agent, use the `messagebox` tool. It ensures only the recipient can decrypt the data.
|
|
23
|
+
|
|
24
|
+
```javascript
|
|
25
|
+
messagebox({
|
|
26
|
+
action: "send",
|
|
27
|
+
recipientKey: "03abc...",
|
|
28
|
+
body: "Here is the private report: ..."
|
|
29
|
+
})
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### Checking for Instructions
|
|
33
|
+
If you are part of a coordinated task, check your `inbox` periodically for new messages from your peers.
|
|
34
|
+
|
|
35
|
+
### Direct Payments
|
|
36
|
+
Use `pay` for simple peer-to-peer transfers that don't require an overlay service advertisement.
|
|
37
|
+
|
|
38
|
+
```javascript
|
|
39
|
+
messagebox({
|
|
40
|
+
action: "pay",
|
|
41
|
+
recipientKey: "03abc...",
|
|
42
|
+
sats: 50
|
|
43
|
+
})
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Etiquette & Security
|
|
47
|
+
1. **Acknowledge**: Always call `acknowledge` after you have successfully processed and saved a message. This keeps the network efficient.
|
|
48
|
+
2. **Verify**: Before trusting instructions in a message, verify the `senderKey` against your known contacts or task coordinators.
|
package/index.ts
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import os from "os";
|
|
4
|
+
|
|
5
|
+
export default definePluginEntry({
|
|
6
|
+
setup: async (api) => {
|
|
7
|
+
// Capture configuration
|
|
8
|
+
const config = api.getConfig?.()?.plugins?.entries?.['openclaw-messagebox-plugin']?.config || {};
|
|
9
|
+
const host = config.host || 'https://msg.bsv.direct';
|
|
10
|
+
const walletDir = config.walletDir || path.join(os.homedir(), '.openclaw', 'bsv-wallet');
|
|
11
|
+
|
|
12
|
+
api.logger.info(`Initializing MessageBox Plugin (host: ${host})`);
|
|
13
|
+
|
|
14
|
+
// Register the messagebox tool
|
|
15
|
+
api.registerTool({
|
|
16
|
+
name: "messagebox",
|
|
17
|
+
description: "Secure P2P encrypted messaging and payments",
|
|
18
|
+
parameters: {
|
|
19
|
+
type: "object",
|
|
20
|
+
properties: {
|
|
21
|
+
action: {
|
|
22
|
+
type: "string",
|
|
23
|
+
enum: ["send", "inbox", "pay", "acknowledge", "status"],
|
|
24
|
+
description: "Action to perform"
|
|
25
|
+
},
|
|
26
|
+
recipientKey: {
|
|
27
|
+
type: "string",
|
|
28
|
+
description: "Target identity public key (hex)"
|
|
29
|
+
},
|
|
30
|
+
body: {
|
|
31
|
+
type: "string",
|
|
32
|
+
description: "Message content (will be encrypted)"
|
|
33
|
+
},
|
|
34
|
+
sats: {
|
|
35
|
+
type: "number",
|
|
36
|
+
description: "Amount for P2P payment"
|
|
37
|
+
},
|
|
38
|
+
messageIds: {
|
|
39
|
+
type: "array",
|
|
40
|
+
items: { type: "string" },
|
|
41
|
+
description: "IDs of messages to acknowledge"
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
required: ["action"]
|
|
45
|
+
},
|
|
46
|
+
execute: async (id, params) => {
|
|
47
|
+
// TODO: Implement execution logic using MessageBoxClient
|
|
48
|
+
return {
|
|
49
|
+
content: [{
|
|
50
|
+
type: "text",
|
|
51
|
+
text: `Action '${params.action}' received. (Implementation pending logic development)`
|
|
52
|
+
}]
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
// Register background service for live message listening
|
|
58
|
+
api.registerService({
|
|
59
|
+
id: "messagebox-listener",
|
|
60
|
+
start: async () => {
|
|
61
|
+
api.logger.info("Starting MessageBox WebSocket listener...");
|
|
62
|
+
// TODO: Implement WebSocket listener using MessageBoxClient.listenForLiveMessages
|
|
63
|
+
},
|
|
64
|
+
stop: async () => {
|
|
65
|
+
api.logger.info("Stopping MessageBox WebSocket listener...");
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
});
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "openclaw-messagebox-plugin",
|
|
3
|
+
"name": "BSV MessageBox P2P",
|
|
4
|
+
"description": "Secure P2P encrypted messaging and payments for AI agents",
|
|
5
|
+
"version": "0.1.0",
|
|
6
|
+
"skills": [
|
|
7
|
+
"./SKILL.md"
|
|
8
|
+
],
|
|
9
|
+
"configSchema": {
|
|
10
|
+
"type": "object",
|
|
11
|
+
"additionalProperties": false,
|
|
12
|
+
"properties": {
|
|
13
|
+
"host": {
|
|
14
|
+
"type": "string",
|
|
15
|
+
"default": "https://msg.bsv.direct",
|
|
16
|
+
"description": "MessageBox server host URL"
|
|
17
|
+
},
|
|
18
|
+
"walletDir": {
|
|
19
|
+
"type": "string",
|
|
20
|
+
"description": "Path to BSV wallet storage (defaults to ~/.openclaw/bsv-wallet)"
|
|
21
|
+
},
|
|
22
|
+
"dbPath": {
|
|
23
|
+
"type": "string",
|
|
24
|
+
"description": "Path to local SQLite database for messages"
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"uiHints": {
|
|
29
|
+
"host": {
|
|
30
|
+
"label": "MessageBox Host",
|
|
31
|
+
"placeholder": "https://msg.bsv.direct"
|
|
32
|
+
},
|
|
33
|
+
"walletDir": {
|
|
34
|
+
"label": "Wallet Directory",
|
|
35
|
+
"advanced": true
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "openclaw-messagebox-plugin",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "OpenClaw plugin for P2P encrypted messaging and payments via BSV MessageBox",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"files": [
|
|
8
|
+
"index.ts",
|
|
9
|
+
"openclaw.plugin.json",
|
|
10
|
+
"src/",
|
|
11
|
+
"dist/",
|
|
12
|
+
"SKILL.md",
|
|
13
|
+
"README.md"
|
|
14
|
+
],
|
|
15
|
+
"scripts": {
|
|
16
|
+
"build": "tsc",
|
|
17
|
+
"lint": "eslint src/**/*.ts",
|
|
18
|
+
"test": "npx tsx src/**/*.test.ts"
|
|
19
|
+
},
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"@bsv/sdk": "^2.0.13",
|
|
22
|
+
"@bsv/message-box-client": "^1.0.0",
|
|
23
|
+
"better-sqlite3": "^12.8.0",
|
|
24
|
+
"knex": "^3.2.8",
|
|
25
|
+
"dotenv": "^17.3.1"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"@types/node": "^25.5.0",
|
|
29
|
+
"typescript": "^6.0.2",
|
|
30
|
+
"eslint": "^10.1.0"
|
|
31
|
+
},
|
|
32
|
+
"openclaw": {
|
|
33
|
+
"extensions": [
|
|
34
|
+
"./index.ts"
|
|
35
|
+
]
|
|
36
|
+
},
|
|
37
|
+
"keywords": [
|
|
38
|
+
"openclaw",
|
|
39
|
+
"plugin",
|
|
40
|
+
"bsv",
|
|
41
|
+
"p2p",
|
|
42
|
+
"messaging",
|
|
43
|
+
"encryption"
|
|
44
|
+
],
|
|
45
|
+
"author": "Tomás Díaz",
|
|
46
|
+
"license": "MIT"
|
|
47
|
+
}
|
package/src/client.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { MessageBoxClient } from '@bsv/message-box-client';
|
|
2
|
+
import { MessageBoxConfig, MessageRecord } from './types.js';
|
|
3
|
+
|
|
4
|
+
export class MessageBoxManager {
|
|
5
|
+
private client: MessageBoxClient;
|
|
6
|
+
|
|
7
|
+
constructor(config: MessageBoxConfig) {
|
|
8
|
+
// Note: MessageBoxClient requires a WalletClient/Identity
|
|
9
|
+
// This will be initialized in the setup method
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
async send(recipientKey: string, body: string, box: string = 'default'): Promise<string> {
|
|
13
|
+
// 1. Encrypt body for recipient
|
|
14
|
+
// 2. Call client.sendMessage
|
|
15
|
+
return "msg_id";
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
async poll(box: string = 'default'): Promise<MessageRecord[]> {
|
|
19
|
+
// 1. Call client.listMessages
|
|
20
|
+
// 2. Decrypt and format
|
|
21
|
+
return [];
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async acknowledge(messageIds: string[]) {
|
|
25
|
+
// Call client.acknowledgeMessage
|
|
26
|
+
}
|
|
27
|
+
}
|
package/src/store.ts
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import knex, { Knex } from 'knex';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import fs from 'fs';
|
|
4
|
+
import { MessageRecord } from './types.js';
|
|
5
|
+
|
|
6
|
+
export class MessageStore {
|
|
7
|
+
private db: Knex;
|
|
8
|
+
|
|
9
|
+
constructor(dbPath: string) {
|
|
10
|
+
const dir = path.dirname(dbPath);
|
|
11
|
+
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
12
|
+
|
|
13
|
+
this.db = knex({
|
|
14
|
+
client: 'better-sqlite3',
|
|
15
|
+
connection: { filename: dbPath },
|
|
16
|
+
useNullAsDefault: true
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async init() {
|
|
21
|
+
if (!(await this.db.schema.hasTable('messages'))) {
|
|
22
|
+
await this.db.schema.createTable('messages', (table) => {
|
|
23
|
+
table.string('id').primary();
|
|
24
|
+
table.string('senderKey');
|
|
25
|
+
table.string('recipientKey');
|
|
26
|
+
table.text('body');
|
|
27
|
+
table.string('box');
|
|
28
|
+
table.integer('ts');
|
|
29
|
+
table.boolean('acknowledged').defaultTo(false);
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async saveMessage(msg: MessageRecord) {
|
|
35
|
+
await this.db('messages').insert(msg).onConflict('id').ignore();
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async getInbox(limit: number = 50) {
|
|
39
|
+
return this.db('messages').orderBy('ts', 'desc').limit(limit);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async markAcknowledged(ids: string[]) {
|
|
43
|
+
await this.db('messages').whereIn('id', ids).update({ acknowledged: true });
|
|
44
|
+
}
|
|
45
|
+
}
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface MessageRecord {
|
|
2
|
+
id: string;
|
|
3
|
+
senderKey: string;
|
|
4
|
+
recipientKey: string;
|
|
5
|
+
body: string;
|
|
6
|
+
box: string;
|
|
7
|
+
ts: number;
|
|
8
|
+
acknowledged: boolean;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface MessageBoxConfig {
|
|
12
|
+
host: string;
|
|
13
|
+
walletDir: string;
|
|
14
|
+
dbPath?: string;
|
|
15
|
+
}
|