@resciencelab/agent-world-network 1.0.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.
Files changed (50) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +357 -0
  3. package/dist/address.d.ts +5 -0
  4. package/dist/address.d.ts.map +1 -0
  5. package/dist/address.js +44 -0
  6. package/dist/address.js.map +1 -0
  7. package/dist/channel.d.ts +107 -0
  8. package/dist/channel.d.ts.map +1 -0
  9. package/dist/channel.js +94 -0
  10. package/dist/channel.js.map +1 -0
  11. package/dist/identity.d.ts +31 -0
  12. package/dist/identity.d.ts.map +1 -0
  13. package/dist/identity.js +312 -0
  14. package/dist/identity.js.map +1 -0
  15. package/dist/index.d.ts +2 -0
  16. package/dist/index.d.ts.map +1 -0
  17. package/dist/index.js +812 -0
  18. package/dist/index.js.map +1 -0
  19. package/dist/peer-client.d.ts +26 -0
  20. package/dist/peer-client.d.ts.map +1 -0
  21. package/dist/peer-client.js +199 -0
  22. package/dist/peer-client.js.map +1 -0
  23. package/dist/peer-db.d.ts +32 -0
  24. package/dist/peer-db.d.ts.map +1 -0
  25. package/dist/peer-db.js +299 -0
  26. package/dist/peer-db.js.map +1 -0
  27. package/dist/peer-server.d.ts +36 -0
  28. package/dist/peer-server.d.ts.map +1 -0
  29. package/dist/peer-server.js +319 -0
  30. package/dist/peer-server.js.map +1 -0
  31. package/dist/transport-quic.d.ts +32 -0
  32. package/dist/transport-quic.d.ts.map +1 -0
  33. package/dist/transport-quic.js +195 -0
  34. package/dist/transport-quic.js.map +1 -0
  35. package/dist/transport.d.ts +55 -0
  36. package/dist/transport.d.ts.map +1 -0
  37. package/dist/transport.js +80 -0
  38. package/dist/transport.js.map +1 -0
  39. package/dist/types.d.ts +107 -0
  40. package/dist/types.d.ts.map +1 -0
  41. package/dist/types.js +4 -0
  42. package/dist/types.js.map +1 -0
  43. package/openclaw.plugin.json +77 -0
  44. package/package.json +62 -0
  45. package/scripts/release.sh.bak +113 -0
  46. package/scripts/sync-version.mjs +19 -0
  47. package/skills/awn/SKILL.md +95 -0
  48. package/skills/awn/references/discovery.md +71 -0
  49. package/skills/awn/references/flows.md +84 -0
  50. package/skills/awn/references/install.md +38 -0
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Transport abstraction layer for AWN P2P communication.
3
+ *
4
+ * Defines the interface that all transport backends must implement,
5
+ * plus the TransportManager that handles automatic selection.
6
+ */
7
+ import { Identity, Endpoint } from "./types";
8
+ export type TransportId = "quic" | "tcp";
9
+ export interface TransportEndpoint {
10
+ transport: TransportId;
11
+ address: string;
12
+ port: number;
13
+ priority: number;
14
+ ttl: number;
15
+ }
16
+ export interface Transport {
17
+ readonly id: TransportId;
18
+ readonly address: string;
19
+ /**
20
+ * Initialize and start the transport.
21
+ * Returns true if the transport is available and started successfully.
22
+ */
23
+ start(identity: Identity, opts?: Record<string, unknown>): Promise<boolean>;
24
+ /** Gracefully shut down the transport. */
25
+ stop(): Promise<void>;
26
+ /** Whether this transport is currently active and can send/receive. */
27
+ isActive(): boolean;
28
+ /**
29
+ * Send raw data to a target address on this transport.
30
+ */
31
+ send(target: string, data: Buffer): Promise<void>;
32
+ /** Register a handler for incoming data on this transport. */
33
+ onMessage(handler: (from: string, data: Buffer) => void): void;
34
+ /** Get the endpoint descriptor for peer announcements. */
35
+ getEndpoint(): TransportEndpoint;
36
+ }
37
+ /**
38
+ * TransportManager handles transport selection and lifecycle.
39
+ *
40
+ * Selection order: first registered transport that starts successfully becomes active.
41
+ */
42
+ export declare class TransportManager {
43
+ private _transports;
44
+ private _active;
45
+ private _all;
46
+ register(transport: Transport): void;
47
+ start(identity: Identity, opts?: Record<string, unknown>): Promise<Transport | null>;
48
+ stop(): Promise<void>;
49
+ get active(): Transport | null;
50
+ get(id: TransportId): Transport | undefined;
51
+ getAll(): Transport[];
52
+ getEndpoints(): Endpoint[];
53
+ resolveTransport(address: string): Transport | null;
54
+ }
55
+ //# sourceMappingURL=transport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AAE5C,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,KAAK,CAAA;AAExC,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,WAAW,CAAA;IACtB,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,CAAA;IAChB,GAAG,EAAE,MAAM,CAAA;CACZ;AAED,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,EAAE,EAAE,WAAW,CAAA;IACxB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IAExB;;;OAGG;IACH,KAAK,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IAE3E,0CAA0C;IAC1C,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IAErB,uEAAuE;IACvE,QAAQ,IAAI,OAAO,CAAA;IAEnB;;OAEG;IACH,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAEjD,8DAA8D;IAC9D,SAAS,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI,CAAA;IAE9D,0DAA0D;IAC1D,WAAW,IAAI,iBAAiB,CAAA;CACjC;AAED;;;;GAIG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,WAAW,CAAyC;IAC5D,OAAO,CAAC,OAAO,CAAyB;IACxC,OAAO,CAAC,IAAI,CAAkB;IAE9B,QAAQ,CAAC,SAAS,EAAE,SAAS,GAAG,IAAI;IAI9B,KAAK,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC;IAmBpF,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAQ3B,IAAI,MAAM,IAAI,SAAS,GAAG,IAAI,CAE7B;IAED,GAAG,CAAC,EAAE,EAAE,WAAW,GAAG,SAAS,GAAG,SAAS;IAI3C,MAAM,IAAI,SAAS,EAAE;IAIrB,YAAY,IAAI,QAAQ,EAAE;IAmB1B,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI;CAOpD"}
@@ -0,0 +1,80 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TransportManager = void 0;
4
+ /**
5
+ * TransportManager handles transport selection and lifecycle.
6
+ *
7
+ * Selection order: first registered transport that starts successfully becomes active.
8
+ */
9
+ class TransportManager {
10
+ _transports = new Map();
11
+ _active = null;
12
+ _all = [];
13
+ register(transport) {
14
+ this._all.push(transport);
15
+ }
16
+ async start(identity, opts) {
17
+ for (const t of this._all) {
18
+ console.log(`[transport] Trying ${t.id}...`);
19
+ const ok = await t.start(identity, opts);
20
+ if (ok) {
21
+ this._transports.set(t.id, t);
22
+ if (!this._active) {
23
+ this._active = t;
24
+ console.log(`[transport] Active transport: ${t.id} (${t.address})`);
25
+ }
26
+ else {
27
+ console.log(`[transport] Fallback available: ${t.id} (${t.address})`);
28
+ }
29
+ }
30
+ else {
31
+ console.log(`[transport] ${t.id} not available`);
32
+ }
33
+ }
34
+ return this._active;
35
+ }
36
+ async stop() {
37
+ for (const t of this._transports.values()) {
38
+ await t.stop();
39
+ }
40
+ this._transports.clear();
41
+ this._active = null;
42
+ }
43
+ get active() {
44
+ return this._active;
45
+ }
46
+ get(id) {
47
+ return this._transports.get(id);
48
+ }
49
+ getAll() {
50
+ return Array.from(this._transports.values());
51
+ }
52
+ getEndpoints() {
53
+ const endpoints = [];
54
+ for (const t of this._transports.values()) {
55
+ try {
56
+ const ep = t.getEndpoint();
57
+ endpoints.push({
58
+ transport: ep.transport,
59
+ address: ep.address,
60
+ port: ep.port,
61
+ priority: ep.priority,
62
+ ttl: ep.ttl,
63
+ });
64
+ }
65
+ catch {
66
+ continue;
67
+ }
68
+ }
69
+ return endpoints;
70
+ }
71
+ resolveTransport(address) {
72
+ // host:port with digits → QUIC
73
+ if (address.includes(":") && /\d+$/.test(address)) {
74
+ return this._transports.get("quic") ?? this._active;
75
+ }
76
+ return this._active;
77
+ }
78
+ }
79
+ exports.TransportManager = TransportManager;
80
+ //# sourceMappingURL=transport.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transport.js","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,107 @@
1
+ export type TransportType = "quic" | "tailscale" | "tcp";
2
+ export interface Endpoint {
3
+ transport: TransportType;
4
+ address: string;
5
+ port: number;
6
+ priority: number;
7
+ ttl: number;
8
+ }
9
+ export interface Identity {
10
+ agentId: string;
11
+ publicKey: string;
12
+ privateKey: string;
13
+ }
14
+ export interface P2PMessage {
15
+ from: string;
16
+ publicKey: string;
17
+ event: "chat" | "ping" | "pong" | "leave" | string;
18
+ content: string;
19
+ timestamp: number;
20
+ signature: string;
21
+ }
22
+ export interface PeerAnnouncement {
23
+ from: string;
24
+ publicKey: string;
25
+ alias?: string;
26
+ version?: string;
27
+ endpoints: Endpoint[];
28
+ capabilities?: string[];
29
+ timestamp: number;
30
+ signature: string;
31
+ peers: Array<{
32
+ agentId: string;
33
+ publicKey: string;
34
+ alias?: string;
35
+ endpoints: Endpoint[];
36
+ lastSeen: number;
37
+ }>;
38
+ }
39
+ export interface PeerRecord {
40
+ agentId: string;
41
+ publicKey: string;
42
+ alias: string;
43
+ endpoints: Endpoint[];
44
+ capabilities: string[];
45
+ firstSeen: number;
46
+ lastSeen: number;
47
+ }
48
+ export interface DiscoveredPeerRecord extends PeerRecord {
49
+ tofuCachedAt?: number;
50
+ discoveredVia?: string;
51
+ source: "manual" | "bootstrap" | "gossip" | "gateway";
52
+ version?: string;
53
+ }
54
+ export interface PluginConfig {
55
+ agent_name?: string;
56
+ peer_port?: number;
57
+ quic_port?: number;
58
+ data_dir?: string;
59
+ tofu_ttl_days?: number;
60
+ /** Explicitly advertised public address (IP or hostname) for peer endpoints. */
61
+ advertise_address?: string;
62
+ /** Explicitly advertised public port for QUIC transport. */
63
+ advertise_port?: number;
64
+ }
65
+ export interface AwRequestHeaders {
66
+ "X-AgentWorld-Version": string;
67
+ "X-AgentWorld-From": string;
68
+ "X-AgentWorld-KeyId": string;
69
+ "X-AgentWorld-Timestamp": string;
70
+ "Content-Digest": string;
71
+ "X-AgentWorld-Signature": string;
72
+ }
73
+ export interface AwResponseHeaders {
74
+ "X-AgentWorld-Version": string;
75
+ "X-AgentWorld-From": string;
76
+ "X-AgentWorld-KeyId": string;
77
+ "X-AgentWorld-Timestamp": string;
78
+ "Content-Digest": string;
79
+ "X-AgentWorld-Signature": string;
80
+ }
81
+ export interface KeyRotationIdentity {
82
+ agentId: string;
83
+ kid: string;
84
+ publicKeyMultibase: string;
85
+ }
86
+ export interface KeyRotationProof {
87
+ protected: string;
88
+ signature: string;
89
+ }
90
+ export interface KeyRotationRequestV2 {
91
+ type: "agentworld-identity-rotation";
92
+ version: string;
93
+ logicalCardUrl?: string;
94
+ oldAgentId: string;
95
+ newAgentId: string;
96
+ oldIdentity: KeyRotationIdentity;
97
+ newIdentity: KeyRotationIdentity;
98
+ timestamp: number;
99
+ effectiveAt?: string;
100
+ overlapUntil?: string;
101
+ reason?: string;
102
+ proofs: {
103
+ signedByOld: KeyRotationProof;
104
+ signedByNew: KeyRotationProof;
105
+ };
106
+ }
107
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js ADDED
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+ // ── Transport types ──────────────────────────────────────────────────────────
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":";AAAA,gFAAgF"}
@@ -0,0 +1,77 @@
1
+ {
2
+ "id": "awn",
3
+ "name": "Agent World Network",
4
+ "description": "Agent World Network — world-scoped agent discovery and communication for OpenClaw",
5
+ "version": "1.0.0",
6
+ "channels": [
7
+ "awn"
8
+ ],
9
+ "skills": [
10
+ "./skills/awn"
11
+ ],
12
+ "configSchema": {
13
+ "type": "object",
14
+ "additionalProperties": false,
15
+ "properties": {
16
+ "agent_name": {
17
+ "type": "string",
18
+ "description": "Human-readable name for this agent instance, shared with peers during discovery (e.g. \"Alice's coder\")"
19
+ },
20
+ "peer_port": {
21
+ "type": "integer",
22
+ "default": 8099,
23
+ "description": "Local port for the P2P peer server (HTTP)"
24
+ },
25
+ "quic_port": {
26
+ "type": "integer",
27
+ "default": 8098,
28
+ "description": "Local port for the QUIC/UDP transport (optional fast transport)"
29
+ },
30
+ "advertise_address": {
31
+ "type": "string",
32
+ "description": "Public IP or DNS name to advertise for the QUIC/UDP transport when the listener is bound to a different local interface"
33
+ },
34
+ "advertise_port": {
35
+ "type": "integer",
36
+ "description": "Public UDP port to advertise for the QUIC/UDP transport when it differs from the local listener port"
37
+ },
38
+ "data_dir": {
39
+ "type": "string",
40
+ "description": "Directory to store identity and peer data (default: ~/.openclaw/awn)"
41
+ },
42
+ "tofu_ttl_days": {
43
+ "type": "integer",
44
+ "default": 7,
45
+ "description": "Days before a TOFU public-key binding expires and is re-verified on next contact (default 7)"
46
+ }
47
+ }
48
+ },
49
+ "uiHints": {
50
+ "agent_name": {
51
+ "label": "Agent Name",
52
+ "placeholder": "Alice's coder"
53
+ },
54
+ "peer_port": {
55
+ "label": "Peer Server Port (HTTP)",
56
+ "placeholder": "8099"
57
+ },
58
+ "quic_port": {
59
+ "label": "QUIC Transport Port (UDP)",
60
+ "placeholder": "8098"
61
+ },
62
+ "advertise_address": {
63
+ "label": "Advertised QUIC Address",
64
+ "placeholder": "vpn.example.com"
65
+ },
66
+ "advertise_port": {
67
+ "label": "Advertised QUIC Port",
68
+ "placeholder": "4433"
69
+ },
70
+ "data_dir": {
71
+ "label": "Data Directory"
72
+ },
73
+ "tofu_ttl_days": {
74
+ "label": "TOFU Key Binding TTL (days)"
75
+ }
76
+ }
77
+ }
package/package.json ADDED
@@ -0,0 +1,62 @@
1
+ {
2
+ "name": "@resciencelab/agent-world-network",
3
+ "version": "1.0.0",
4
+ "description": "Agent World Network — world-scoped agent discovery and communication for OpenClaw",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "files": [
8
+ "dist",
9
+ "scripts",
10
+ "openclaw.plugin.json",
11
+ "skills",
12
+ "README.md"
13
+ ],
14
+ "openclaw": {
15
+ "extensions": [
16
+ "./dist/index.js"
17
+ ],
18
+ "channel": {
19
+ "id": "awn",
20
+ "label": "AWN",
21
+ "selectionLabel": "AWN (Agent World Network)",
22
+ "docsPath": "/channels/awn",
23
+ "blurb": "Agent World Network — world-scoped agent communication.",
24
+ "order": 90,
25
+ "aliases": [
26
+ "p2p"
27
+ ]
28
+ },
29
+ "install": {
30
+ "npmSpec": "@resciencelab/agent-world-network",
31
+ "defaultChoice": "npm"
32
+ }
33
+ },
34
+ "scripts": {
35
+ "build": "tsc",
36
+ "dev": "tsc --watch",
37
+ "version": "changeset version && node scripts/sync-version.mjs",
38
+ "release": "npm run build && npm --prefix packages/agent-world-sdk run build && changeset publish && cd packages/agent-world-sdk && npm publish --access public",
39
+ "prepublishOnly": "npm run build"
40
+ },
41
+ "publishConfig": {
42
+ "access": "public"
43
+ },
44
+ "keywords": [
45
+ "openclaw",
46
+ "plugin",
47
+ "p2p",
48
+ "ed25519",
49
+ "agent-network"
50
+ ],
51
+ "license": "MIT",
52
+ "dependencies": {
53
+ "@noble/hashes": "^1.3.3",
54
+ "fastify": "^5.7.4",
55
+ "tweetnacl": "^1.0.3"
56
+ },
57
+ "devDependencies": {
58
+ "@changesets/cli": "^2.30.0",
59
+ "@types/node": "^20.11.5",
60
+ "typescript": "^5.3.3"
61
+ }
62
+ }
@@ -0,0 +1,113 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ # AWN — release script (creates Release PR)
5
+ # Usage:
6
+ # bash scripts/release.sh patch # 0.2.2 → 0.2.3
7
+ # bash scripts/release.sh minor # 0.2.2 → 0.3.0
8
+ # bash scripts/release.sh major # 0.2.2 → 1.0.0
9
+ #
10
+ # Flow:
11
+ # 1. Local: preflight → build+test → version bump → create Release PR
12
+ # 2. CI: PR merge triggers release.yml → tag + GH Release + npm + ClawHub + backmerge
13
+
14
+ LEVEL="${1:-patch}"
15
+
16
+ if [[ "$LEVEL" != "patch" && "$LEVEL" != "minor" && "$LEVEL" != "major" ]]; then
17
+ echo "Usage: bash scripts/release.sh [patch|minor|major]"
18
+ exit 1
19
+ fi
20
+
21
+ echo "=== AWN Release (${LEVEL}) ==="
22
+
23
+ # ── 0. Preflight ─────────────────────────────────────────────────────────────
24
+
25
+ BRANCH=$(git branch --show-current)
26
+ if [[ "$BRANCH" != "main" && "$BRANCH" != "develop" ]]; then
27
+ echo "Error: must be on 'main' or 'develop' branch (currently on '${BRANCH}')"
28
+ exit 1
29
+ fi
30
+
31
+ if [[ -n "$(git status --porcelain)" ]]; then
32
+ echo "Error: working tree is not clean. Commit or stash changes first."
33
+ exit 1
34
+ fi
35
+
36
+ git fetch origin main --quiet
37
+ LOCAL=$(git rev-parse main)
38
+ REMOTE=$(git rev-parse origin/main)
39
+ if [[ "$LOCAL" != "$REMOTE" ]]; then
40
+ echo "Error: local main differs from origin/main. Pull or push first."
41
+ exit 1
42
+ fi
43
+
44
+ # ── 1. Build + test ──────────────────────────────────────────────────────────
45
+
46
+ echo "Building..."
47
+ npm run build
48
+
49
+ echo "Running tests..."
50
+ node --test test/*.test.mjs
51
+
52
+ # ── 2. Version bump ──────────────────────────────────────────────────────────
53
+
54
+ VERSION=$(npm version "$LEVEL" --no-git-tag-version | tr -d 'v')
55
+ echo "New version: ${VERSION}"
56
+
57
+ sed -i '' "s/\"version\": \"[^\"]*\"/\"version\": \"${VERSION}\"/" openclaw.plugin.json
58
+ sed -i '' "s/^version: .*/version: ${VERSION}/" skills/awn/SKILL.md
59
+
60
+ echo "Version synced: package.json, openclaw.plugin.json, skills/awn/SKILL.md"
61
+
62
+ # ── 3. Changelog check ───────────────────────────────────────────────────────
63
+
64
+ if ! grep -q "\[${VERSION}\]" CHANGELOG.md; then
65
+ echo ""
66
+ echo "Warning: CHANGELOG.md does not contain a [${VERSION}] section."
67
+ read -p "Continue without changelog entry? (y/N) " -n 1 -r
68
+ echo
69
+ if [[ ! "$REPLY" =~ ^[Yy]$ ]]; then
70
+ echo "Aborting. Update CHANGELOG.md and re-run."
71
+ git checkout -- package.json package-lock.json openclaw.plugin.json skills/awn/SKILL.md
72
+ exit 1
73
+ fi
74
+ fi
75
+
76
+ # ── 4. Create release branch + PR ────────────────────────────────────────────
77
+
78
+ RELEASE_BRANCH="release/v${VERSION}"
79
+
80
+ git checkout -b "$RELEASE_BRANCH"
81
+ git add -A
82
+ git commit -m "chore: release v${VERSION}"
83
+ git push -u origin "$RELEASE_BRANCH"
84
+
85
+ PR_URL=$(gh pr create \
86
+ --base main \
87
+ --head "$RELEASE_BRANCH" \
88
+ --title "chore: release v${VERSION}" \
89
+ --body "## Release v${VERSION}
90
+
91
+ ### Version bump
92
+ - \`package.json\` → ${VERSION}
93
+ - \`openclaw.plugin.json\` → ${VERSION}
94
+ - \`skills/awn/SKILL.md\` → ${VERSION}
95
+
96
+ ### What happens on merge
97
+ CI (\`.github/workflows/release.yml\`) will automatically:
98
+ 1. Create git tag \`v${VERSION}\`
99
+ 2. Create GitHub Release (triggers npm publish)
100
+ 3. Publish skill to ClawHub
101
+ 4. Backmerge main → develop")
102
+
103
+ echo ""
104
+ echo "=== Release PR created ==="
105
+ echo " ${PR_URL}"
106
+ echo ""
107
+ echo "Next steps:"
108
+ echo " 1. Wait for CI checks to pass"
109
+ echo " 2. Merge the PR (squash)"
110
+ echo " 3. CI handles: tag → GH Release → npm → ClawHub → backmerge"
111
+ echo ""
112
+
113
+ git checkout main
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env node
2
+ // Post-version hook: sync version from package.json → openclaw.plugin.json, SKILL.md, SDK
3
+ import { readFileSync, writeFileSync } from 'fs'
4
+
5
+ const { version } = JSON.parse(readFileSync('package.json', 'utf8'))
6
+
7
+ const plugin = JSON.parse(readFileSync('openclaw.plugin.json', 'utf8'))
8
+ plugin.version = version
9
+ writeFileSync('openclaw.plugin.json', JSON.stringify(plugin, null, 2) + '\n')
10
+
11
+ let skill = readFileSync('skills/awn/SKILL.md', 'utf8')
12
+ skill = skill.replace(/^version: .*/m, `version: "${version}"`)
13
+ writeFileSync('skills/awn/SKILL.md', skill)
14
+
15
+ const sdkPkg = JSON.parse(readFileSync('packages/agent-world-sdk/package.json', 'utf8'))
16
+ sdkPkg.version = version
17
+ writeFileSync('packages/agent-world-sdk/package.json', JSON.stringify(sdkPkg, null, 2) + '\n')
18
+
19
+ console.log(`Synced version ${version} → openclaw.plugin.json, skills/awn/SKILL.md, packages/agent-world-sdk/package.json`)
@@ -0,0 +1,95 @@
1
+ ---
2
+ name: awn
3
+ description: Direct encrypted P2P messaging between OpenClaw agents over HTTP/TCP and QUIC. AWN is world-scoped: peers become visible only after joining a shared world through the Gateway.
4
+ version: "1.0.0"
5
+ metadata:
6
+ openclaw:
7
+ emoji: "🔗"
8
+ homepage: https://github.com/ReScienceLab/agent-world-network
9
+ os:
10
+ - macos
11
+ - linux
12
+ install:
13
+ - kind: node
14
+ package: "@resciencelab/agent-world-network"
15
+ ---
16
+
17
+ # AWN (Agent World Network)
18
+
19
+ Direct agent-to-agent messaging over HTTP/TCP and QUIC. Messages are Ed25519-signed, and direct delivery is only allowed between peers that share a world.
20
+
21
+ ## Quick Reference
22
+
23
+ | Situation | Action |
24
+ |---|---|
25
+ | User asks for their own agent ID or transport status | `p2p_status()` |
26
+ | User asks who they can currently reach | `p2p_list_peers()` |
27
+ | User wants to find available worlds | `list_worlds()` |
28
+ | User wants to join a known world | `join_world(world_id=...)` |
29
+ | User has a direct world server address | `join_world(address=host:port)` |
30
+ | User wants to send a message | `p2p_send_message(agent_id, message)` |
31
+ | User wants to test connectivity end-to-end | `list_worlds()` -> `join_world()` -> `p2p_send_message()` to a co-member |
32
+ | Sending fails or connectivity looks wrong | Check `p2p_status()` and `p2p_list_peers()` |
33
+
34
+ ## Gateway
35
+
36
+ World Servers announce directly to the Gateway. The Gateway exposes discovered worlds through its `/worlds` endpoint.
37
+
38
+ - Agents discover worlds with `list_worlds()`
39
+ - Agents join a world with `join_world()`
40
+ - World co-members become visible in `p2p_list_peers()` after joining
41
+
42
+ Do not promise global discovery. Reachability is scoped to joined worlds.
43
+
44
+ ## Tool Parameters
45
+
46
+ ### p2p_status
47
+ No parameters.
48
+
49
+ Returns: own agent ID, transport status, and joined worlds.
50
+
51
+ ### p2p_list_peers
52
+ - `capability_prefix` (optional): capability prefix filter such as `world:` or `world:pixel-city`
53
+
54
+ Returns: peer agent ID, alias, capabilities, timestamps, and known endpoints.
55
+
56
+ ### p2p_send_message
57
+ - `agent_id` (required): recipient's agent ID
58
+ - `message` (required): text content
59
+ - `event` (optional): event type, defaults to `"chat"`
60
+
61
+ ### list_worlds
62
+ No parameters.
63
+
64
+ Returns: available worlds from the Gateway.
65
+
66
+ ### join_world
67
+ - `world_id` (optional): world ID returned by `list_worlds()`
68
+ - `address` (optional): direct world server address such as `example.com:8099`
69
+ - `alias` (optional): display name to present while joining
70
+
71
+ Provide either `world_id` or `address`.
72
+
73
+ ## Inbound Messages
74
+
75
+ Incoming messages appear automatically in the OpenClaw chat UI under the **AWN** channel.
76
+
77
+ ## Error Handling
78
+
79
+ | Error | Diagnosis |
80
+ |---|---|
81
+ | `No worlds found` | Gateway is unreachable or no worlds registered. Retry later or join directly by address. |
82
+ | `Join world fails` | The world server is offline, the `world_id` is stale, or the direct address is invalid. |
83
+ | `Message rejected (403)` | Sender and recipient do not currently share a joined world. |
84
+ | TOFU key mismatch (403) | Peer rotated keys or was reinstalled. Wait for TTL expiry or verify the new identity out of band. |
85
+ | QUIC disabled | `advertise_address` is not configured; HTTP/TCP remains available. |
86
+
87
+ ## Rules
88
+
89
+ - Always `join_world` before messaging a new peer. Joining populates the visible co-member list.
90
+ - Never invent agent IDs or world IDs. Ask the user or fetch them from tools.
91
+ - Agent IDs in current builds are stable `aw:sha256:<64hex>` strings.
92
+ - Prefer `list_worlds()` before `join_world(world_id=...)`.
93
+ - If the user gives a direct world address, use `join_world(address=...)` instead of guessing a world ID.
94
+
95
+ **Reference**: `references/flows.md` (interaction examples)