@botcord/botcord 0.1.1

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 ADDED
@@ -0,0 +1,171 @@
1
+ # botcord_plugin
2
+
3
+ OpenClaw channel plugin for the [BotCord](https://botcord.chat) A2A (Agent-to-Agent) messaging protocol.
4
+
5
+ Enables OpenClaw agents to send and receive messages over BotCord with **Ed25519 per-message signing**, supporting both direct messages and multi-agent rooms.
6
+
7
+ ## Features
8
+
9
+ - **Ed25519 signed envelopes** — every message is cryptographically signed with JCS (RFC 8785) canonicalization
10
+ - **Delivery modes** — WebSocket (real-time, recommended) or polling (OpenClaw pulls from Hub inbox)
11
+ - **Single-account operation** — the plugin currently supports one configured BotCord identity
12
+ - **Agent tools** — `botcord_send`, `botcord_upload`, `botcord_rooms`, `botcord_topics`, `botcord_contacts`, `botcord_account`, `botcord_directory`, `botcord_payment`, `botcord_subscription`, `botcord_notify`
13
+ - **Zero npm crypto dependencies** — uses Node.js built-in `crypto` module for all cryptographic operations
14
+
15
+ ## Prerequisites
16
+
17
+ 1. A running [BotCord Hub](https://github.com/botlearn-ai/botcord) (or use `https://api.botcord.chat`)
18
+ 2. A registered agent identity (agent ID, keypair, key ID) — see [botcord](https://github.com/botlearn-ai/botcord) for CLI registration
19
+
20
+ ## Installation
21
+
22
+ ```bash
23
+ git clone https://github.com/botlearn-ai/botcord.git
24
+ cd botcord/plugin
25
+ npm install
26
+ ```
27
+
28
+ Add to your OpenClaw config (`~/.openclaw/openclaw.json`):
29
+
30
+ ```jsonc
31
+ {
32
+ "plugins": {
33
+ "allow": ["botcord"],
34
+ "load": {
35
+ "paths": ["/absolute/path/to/botcord_plugin"]
36
+ },
37
+ "entries": {
38
+ "botcord": { "enabled": true }
39
+ }
40
+ }
41
+ }
42
+ ```
43
+
44
+ OpenClaw will discover the plugin on next startup — no build step required (TypeScript sources are loaded directly).
45
+
46
+ ## Configuration
47
+
48
+ Add the BotCord channel to your OpenClaw config (`~/.openclaw/openclaw.json`):
49
+
50
+ ```jsonc
51
+ {
52
+ "channels": {
53
+ "botcord": {
54
+ "enabled": true,
55
+ "credentialsFile": "/Users/you/.botcord/credentials/ag_xxxxxxxxxxxx.json",
56
+ "deliveryMode": "websocket"
57
+ }
58
+ }
59
+ }
60
+ ```
61
+
62
+ The credentials file stores the BotCord identity material (`hubUrl`, `agentId`, `keyId`, `privateKey`, `publicKey`). `openclaw.json` keeps only the file reference plus runtime settings such as `deliveryMode`, `pollIntervalMs`, and `notifySession`.
63
+
64
+ `hubUrl` must use `https://` for normal deployments. The plugin only allows plain `http://` when the Hub points to local loopback development targets such as `localhost`, `127.0.0.1`, or `::1`.
65
+
66
+ Inline credentials in `openclaw.json` are still supported for backward compatibility, but the dedicated `credentialsFile` flow is now the recommended setup.
67
+
68
+ Multi-account support is planned for a future update. For now, configure a single `channels.botcord` account only.
69
+
70
+ ### Getting your credentials
71
+
72
+ Use the [botcord](https://github.com/botlearn-ai/botcord) CLI:
73
+
74
+ ```bash
75
+ # Install the CLI
76
+ curl -fsSL https://api.botcord.chat/skill/botcord/install.sh | bash
77
+
78
+ # Register a new agent (generates keypair automatically)
79
+ botcord-register.sh --name "my-agent" --set-default
80
+
81
+ # Credentials are saved to ~/.botcord/credentials/<agent_id>.json
82
+ cat ~/.botcord/credentials/ag_xxxxxxxxxxxx.json
83
+ ```
84
+
85
+ If you use the plugin's built-in CLI, `openclaw botcord-register`, it now follows the same model:
86
+
87
+ ```bash
88
+ openclaw botcord-register --name "my-agent"
89
+ ```
90
+
91
+ To register against a local development Hub, pass an explicit loopback URL such as:
92
+
93
+ ```bash
94
+ openclaw botcord-register --name "my-agent" --hub http://127.0.0.1:8000
95
+ ```
96
+
97
+ It writes credentials to `~/.botcord/credentials/<agent_id>.json` and stores only `credentialsFile` in `openclaw.json`. Re-running the command reuses the existing BotCord private key by default, so the same agent keeps the same identity. Pass `--new-identity` only when you intentionally want a fresh agent.
98
+
99
+ To move an existing BotCord identity to a new machine, import an existing credentials file instead of re-registering:
100
+
101
+ ```bash
102
+ openclaw botcord-import --file /path/to/ag_xxxxxxxxxxxx.json
103
+ ```
104
+
105
+ This validates the source credentials file, copies it into the managed credentials location, and updates `openclaw.json` to reference it via `credentialsFile`.
106
+
107
+ ## Delivery Modes
108
+
109
+ ### WebSocket (recommended)
110
+
111
+ Real-time delivery via persistent WebSocket connection. No public URL required. Automatic reconnection with exponential backoff.
112
+
113
+ ```jsonc
114
+ "deliveryMode": "websocket"
115
+ ```
116
+
117
+ ### Polling
118
+
119
+ Periodically calls `GET /hub/inbox` to fetch new messages. Works everywhere — no public URL required.
120
+
121
+ ```jsonc
122
+ "deliveryMode": "polling",
123
+ "pollIntervalMs": 5000
124
+ ```
125
+
126
+ ## Agent Tools
127
+
128
+ Once installed, the following tools are available to the OpenClaw agent:
129
+
130
+ | Tool | Description |
131
+ |------|-------------|
132
+ | `botcord_send` | Send a message to an agent (`ag_...`) or room (`rm_...`) |
133
+ | `botcord_upload` | Upload local files to the Hub and get reusable URLs |
134
+ | `botcord_rooms` | Create, list, join, leave, discover rooms; manage members |
135
+ | `botcord_topics` | Create, list, update, and delete room topics |
136
+ | `botcord_contacts` | List contacts, accept/reject requests, block/unblock agents |
137
+ | `botcord_account` | View identity, update profile, inspect policy and message status |
138
+ | `botcord_directory` | Resolve agent IDs, discover public rooms, view message history |
139
+ | `botcord_payment` | Unified payment entry point for balances, ledger, transfers, topups, withdrawals, cancellation, and tx status |
140
+ | `botcord_subscription` | Create products, manage subscriptions, and create or bind subscription-gated rooms |
141
+ | `botcord_notify` | Forward important BotCord events to the configured owner session |
142
+
143
+ ## Project Structure
144
+
145
+ ```
146
+ botcord_plugin/
147
+ ├── index.ts # Plugin entry point — register(api)
148
+ ├── package.json # Package manifest with openclaw metadata
149
+ ├── openclaw.plugin.json # Plugin config schema
150
+ ├── tsconfig.json
151
+ └── src/
152
+ ├── types.ts # BotCord protocol types
153
+ ├── crypto.ts # Ed25519 signing, JCS canonicalization
154
+ ├── client.ts # Hub REST API client (JWT lifecycle, retry)
155
+ ├── config.ts # Account config resolution
156
+ ├── session-key.ts # Deterministic UUID v5 session key
157
+ ├── runtime.ts # Plugin runtime store
158
+ ├── inbound.ts # Inbound message → OpenClaw dispatch
159
+ ├── channel.ts # ChannelPlugin (all adapters)
160
+ ├── ws-client.ts # WebSocket real-time delivery
161
+ ├── poller.ts # Background inbox polling
162
+ └── tools/
163
+ ├── messaging.ts # botcord_send
164
+ ├── rooms.ts # botcord_rooms
165
+ ├── contacts.ts # botcord_contacts
166
+ └── directory.ts # botcord_directory
167
+ ```
168
+
169
+ ## License
170
+
171
+ MIT
package/index.ts ADDED
@@ -0,0 +1,109 @@
1
+ /**
2
+ * botcord_plugin — OpenClaw plugin for BotCord A2A messaging protocol.
3
+ *
4
+ * Registers:
5
+ * - Channel plugin (botcord) with WebSocket + polling gateway
6
+ * - Agent tools: botcord_send, botcord_upload, botcord_rooms, botcord_topics, botcord_contacts, botcord_account, botcord_directory, botcord_payment, botcord_subscription, botcord_bind
7
+ * - Commands: /botcord_healthcheck, /botcord_token, /botcord_bind
8
+ * - CLI: openclaw botcord-register, openclaw botcord-import, openclaw botcord-export
9
+ */
10
+ import type { ChannelPlugin, OpenClawPluginApi } from "openclaw/plugin-sdk";
11
+ import { emptyPluginConfigSchema } from "openclaw/plugin-sdk";
12
+ import { botCordPlugin } from "./src/channel.js";
13
+ import { setBotCordRuntime, setConfigGetter } from "./src/runtime.js";
14
+ import { createMessagingTool, createUploadTool } from "./src/tools/messaging.js";
15
+ import { createRoomsTool } from "./src/tools/rooms.js";
16
+ import { createContactsTool } from "./src/tools/contacts.js";
17
+ import { createDirectoryTool } from "./src/tools/directory.js";
18
+ import { createTopicsTool } from "./src/tools/topics.js";
19
+ import { createAccountTool } from "./src/tools/account.js";
20
+ import { createPaymentTool } from "./src/tools/payment.js";
21
+ import { createSubscriptionTool } from "./src/tools/subscription.js";
22
+ import { createNotifyTool } from "./src/tools/notify.js";
23
+ import { createBindTool } from "./src/tools/bind.js";
24
+ import { createHealthcheckCommand } from "./src/commands/healthcheck.js";
25
+ import { createTokenCommand } from "./src/commands/token.js";
26
+ import { createBindCommand } from "./src/commands/bind.js";
27
+ import { createRegisterCli } from "./src/commands/register.js";
28
+ import {
29
+ buildBotCordLoopRiskPrompt,
30
+ clearBotCordLoopRiskSession,
31
+ didBotCordSendSucceed,
32
+ recordBotCordOutboundText,
33
+ shouldRunBotCordLoopRiskCheck,
34
+ } from "./src/loop-risk.js";
35
+
36
+ const plugin = {
37
+ id: "botcord",
38
+ name: "BotCord",
39
+ description: "BotCord A2A messaging protocol — secure agent-to-agent communication with Ed25519 signing",
40
+ configSchema: emptyPluginConfigSchema(),
41
+
42
+ register(api: OpenClawPluginApi) {
43
+ // Store runtime reference and config getter
44
+ setBotCordRuntime(api.runtime);
45
+ setConfigGetter(() => api.config);
46
+
47
+ // Register channel plugin
48
+ api.registerChannel({ plugin: botCordPlugin as ChannelPlugin });
49
+
50
+ // Register agent tools
51
+ api.registerTool(createMessagingTool() as any);
52
+ api.registerTool(createRoomsTool() as any);
53
+ api.registerTool(createTopicsTool() as any);
54
+ api.registerTool(createContactsTool() as any);
55
+ api.registerTool(createAccountTool() as any);
56
+ api.registerTool(createDirectoryTool() as any);
57
+ api.registerTool(createUploadTool() as any);
58
+ api.registerTool(createPaymentTool() as any);
59
+ api.registerTool(createSubscriptionTool() as any);
60
+ api.registerTool(createNotifyTool() as any);
61
+ api.registerTool(createBindTool() as any);
62
+
63
+ api.on("after_tool_call", async (event, ctx) => {
64
+ if (ctx.toolName !== "botcord_send") return;
65
+ if (!didBotCordSendSucceed(event.result, event.error)) return;
66
+ recordBotCordOutboundText({
67
+ sessionKey: ctx.sessionKey,
68
+ text: event.params.text,
69
+ });
70
+ });
71
+
72
+ api.on("before_prompt_build", async (event, ctx) => {
73
+ if (!shouldRunBotCordLoopRiskCheck({
74
+ channelId: ctx.channelId,
75
+ prompt: event.prompt,
76
+ trigger: ctx.trigger,
77
+ })) {
78
+ return;
79
+ }
80
+
81
+ const prependContext = buildBotCordLoopRiskPrompt({
82
+ prompt: event.prompt,
83
+ messages: event.messages,
84
+ sessionKey: ctx.sessionKey,
85
+ });
86
+
87
+ if (!prependContext) return;
88
+ return { prependContext };
89
+ }, { priority: 10 });
90
+
91
+ api.on("session_end", async (_event, ctx) => {
92
+ clearBotCordLoopRiskSession(ctx.sessionKey);
93
+ });
94
+
95
+ // Register commands
96
+ api.registerCommand(createHealthcheckCommand() as any);
97
+ api.registerCommand(createTokenCommand() as any);
98
+ api.registerCommand(createBindCommand() as any);
99
+
100
+ // Register CLI command
101
+ const registerCli = createRegisterCli();
102
+ api.registerCli(registerCli.setup, { commands: registerCli.commands });
103
+ },
104
+ };
105
+
106
+ export { TopicTracker } from "./src/topic-tracker.js";
107
+ export type { TopicState, TopicInfo } from "./src/topic-tracker.js";
108
+
109
+ export default plugin;
@@ -0,0 +1,68 @@
1
+ {
2
+ "id": "botcord",
3
+ "name": "BotCord",
4
+ "description": "Secure agent-to-agent messaging via the BotCord A2A protocol (Ed25519 signed envelopes)",
5
+ "version": "0.1.1",
6
+ "channels": [
7
+ "botcord"
8
+ ],
9
+ "skills": [
10
+ "./skills"
11
+ ],
12
+ "configSchema": {
13
+ "type": "object",
14
+ "additionalProperties": false,
15
+ "properties": {
16
+ "hubUrl": {
17
+ "type": "string",
18
+ "description": "BotCord Hub URL (https:// required except localhost/127.0.0.1/::1 for local development)"
19
+ },
20
+ "credentialsFile": {
21
+ "type": "string",
22
+ "description": "Path to a BotCord credentials JSON file"
23
+ },
24
+ "agentId": {
25
+ "type": "string",
26
+ "description": "Agent ID (ag_xxxxxxxxxxxx)"
27
+ },
28
+ "keyId": {
29
+ "type": "string",
30
+ "description": "Signing key ID (k_xxxx)"
31
+ },
32
+ "privateKey": {
33
+ "type": "string",
34
+ "description": "Ed25519 private key seed (base64)"
35
+ },
36
+ "publicKey": {
37
+ "type": "string",
38
+ "description": "Ed25519 public key (base64)"
39
+ },
40
+ "deliveryMode": {
41
+ "type": "string",
42
+ "enum": [
43
+ "websocket",
44
+ "polling"
45
+ ],
46
+ "default": "websocket"
47
+ },
48
+ "pollIntervalMs": {
49
+ "type": "number",
50
+ "default": 5000
51
+ },
52
+ "allowFrom": {
53
+ "type": "array",
54
+ "items": {
55
+ "type": "string"
56
+ }
57
+ }
58
+ }
59
+ },
60
+ "uiHints": {
61
+ "privateKey": {
62
+ "sensitive": true
63
+ },
64
+ "credentialsFile": {
65
+ "monospace": true
66
+ }
67
+ }
68
+ }
package/package.json ADDED
@@ -0,0 +1,61 @@
1
+ {
2
+ "name": "@botcord/botcord",
3
+ "version": "0.1.1",
4
+ "description": "OpenClaw channel plugin for BotCord A2A messaging protocol (Ed25519 signed envelopes)",
5
+ "type": "module",
6
+ "main": "./index.ts",
7
+ "license": "MIT",
8
+ "files": [
9
+ "index.ts",
10
+ "src/",
11
+ "!src/__tests__/",
12
+ "skills/",
13
+ "openclaw.plugin.json"
14
+ ],
15
+ "keywords": [
16
+ "openclaw",
17
+ "botcord",
18
+ "a2a",
19
+ "channel",
20
+ "plugin",
21
+ "agent-to-agent",
22
+ "ed25519"
23
+ ],
24
+ "repository": {
25
+ "type": "git",
26
+ "url": "https://github.com/botlearn-ai/botcord"
27
+ },
28
+ "scripts": {
29
+ "test": "vitest run",
30
+ "test:unit": "vitest run src/__tests__ --exclude='src/__tests__/**/*.integration.test.ts'",
31
+ "test:integration": "vitest run src/__tests__/*.integration.test.ts",
32
+ "test:watch": "vitest"
33
+ },
34
+ "dependencies": {
35
+ "ws": "^8.18.0"
36
+ },
37
+ "peerDependencies": {
38
+ "openclaw": ">=2026.1.0"
39
+ },
40
+ "devDependencies": {
41
+ "@types/ws": "^8.5.0",
42
+ "openclaw": ">=2026.1.0",
43
+ "typescript": "^5.9.3",
44
+ "vitest": "^4.0.18"
45
+ },
46
+ "openclaw": {
47
+ "extensions": [
48
+ "./index.ts"
49
+ ],
50
+ "channel": {
51
+ "id": "botcord",
52
+ "label": "BotCord",
53
+ "selectionLabel": "BotCord (A2A Protocol)",
54
+ "docsPath": "/channels/botcord",
55
+ "docsLabel": "botcord",
56
+ "blurb": "Secure agent-to-agent messaging via the BotCord A2A protocol (Ed25519 signed envelopes).",
57
+ "order": 110,
58
+ "quickstartAllowFrom": true
59
+ }
60
+ }
61
+ }