agent-inbox 0.0.1 → 0.1.2

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 (126) hide show
  1. package/CLAUDE.md +113 -0
  2. package/README.md +195 -1
  3. package/dist/federation/address.d.ts +24 -0
  4. package/dist/federation/address.d.ts.map +1 -0
  5. package/dist/federation/address.js +54 -0
  6. package/dist/federation/address.js.map +1 -0
  7. package/dist/federation/connection-manager.d.ts +118 -0
  8. package/dist/federation/connection-manager.d.ts.map +1 -0
  9. package/dist/federation/connection-manager.js +369 -0
  10. package/dist/federation/connection-manager.js.map +1 -0
  11. package/dist/federation/delivery-queue.d.ts +66 -0
  12. package/dist/federation/delivery-queue.d.ts.map +1 -0
  13. package/dist/federation/delivery-queue.js +199 -0
  14. package/dist/federation/delivery-queue.js.map +1 -0
  15. package/dist/federation/index.d.ts +7 -0
  16. package/dist/federation/index.d.ts.map +1 -0
  17. package/dist/federation/index.js +6 -0
  18. package/dist/federation/index.js.map +1 -0
  19. package/dist/federation/routing-engine.d.ts +74 -0
  20. package/dist/federation/routing-engine.d.ts.map +1 -0
  21. package/dist/federation/routing-engine.js +158 -0
  22. package/dist/federation/routing-engine.js.map +1 -0
  23. package/dist/federation/trust.d.ts +39 -0
  24. package/dist/federation/trust.d.ts.map +1 -0
  25. package/dist/federation/trust.js +64 -0
  26. package/dist/federation/trust.js.map +1 -0
  27. package/dist/index.d.ts +60 -2
  28. package/dist/index.d.ts.map +1 -0
  29. package/dist/index.js +217 -18
  30. package/dist/index.js.map +1 -1
  31. package/dist/ipc/ipc-server.d.ts +21 -0
  32. package/dist/ipc/ipc-server.d.ts.map +1 -0
  33. package/dist/ipc/ipc-server.js +173 -0
  34. package/dist/ipc/ipc-server.js.map +1 -0
  35. package/dist/jsonrpc/mail-server.d.ts +45 -0
  36. package/dist/jsonrpc/mail-server.d.ts.map +1 -0
  37. package/dist/jsonrpc/mail-server.js +284 -0
  38. package/dist/jsonrpc/mail-server.js.map +1 -0
  39. package/dist/map/map-client.d.ts +91 -0
  40. package/dist/map/map-client.d.ts.map +1 -0
  41. package/dist/map/map-client.js +202 -0
  42. package/dist/map/map-client.js.map +1 -0
  43. package/dist/mcp/mcp-server.d.ts +23 -0
  44. package/dist/mcp/mcp-server.d.ts.map +1 -0
  45. package/dist/mcp/mcp-server.js +226 -0
  46. package/dist/mcp/mcp-server.js.map +1 -0
  47. package/dist/push/notifier.d.ts +49 -0
  48. package/dist/push/notifier.d.ts.map +1 -0
  49. package/dist/push/notifier.js +150 -0
  50. package/dist/push/notifier.js.map +1 -0
  51. package/dist/registry/warm-registry.d.ts +63 -0
  52. package/dist/registry/warm-registry.d.ts.map +1 -0
  53. package/dist/registry/warm-registry.js +173 -0
  54. package/dist/registry/warm-registry.js.map +1 -0
  55. package/dist/router/message-router.d.ts +44 -0
  56. package/dist/router/message-router.d.ts.map +1 -0
  57. package/dist/router/message-router.js +137 -0
  58. package/dist/router/message-router.js.map +1 -0
  59. package/dist/storage/interface.d.ts +31 -0
  60. package/dist/storage/interface.d.ts.map +1 -0
  61. package/dist/storage/interface.js +2 -0
  62. package/dist/storage/interface.js.map +1 -0
  63. package/dist/storage/memory.d.ts +28 -0
  64. package/dist/storage/memory.d.ts.map +1 -0
  65. package/dist/storage/memory.js +118 -0
  66. package/dist/storage/memory.js.map +1 -0
  67. package/dist/storage/sqlite.d.ts +35 -0
  68. package/dist/storage/sqlite.d.ts.map +1 -0
  69. package/dist/storage/sqlite.js +445 -0
  70. package/dist/storage/sqlite.js.map +1 -0
  71. package/dist/traceability/traceability.d.ts +29 -0
  72. package/dist/traceability/traceability.d.ts.map +1 -0
  73. package/dist/traceability/traceability.js +150 -0
  74. package/dist/traceability/traceability.js.map +1 -0
  75. package/dist/types.d.ts +261 -0
  76. package/dist/types.d.ts.map +1 -0
  77. package/dist/types.js +3 -0
  78. package/dist/types.js.map +1 -0
  79. package/docs/DESIGN.md +1156 -0
  80. package/docs/PLAN.md +545 -0
  81. package/hooks/inbox-hook.mjs +119 -0
  82. package/hooks/register-hook.mjs +69 -0
  83. package/package.json +33 -25
  84. package/rules/agent-inbox.md +78 -0
  85. package/src/federation/address.ts +61 -0
  86. package/src/federation/connection-manager.ts +458 -0
  87. package/src/federation/delivery-queue.ts +222 -0
  88. package/src/federation/index.ts +6 -0
  89. package/src/federation/routing-engine.ts +188 -0
  90. package/src/federation/trust.ts +71 -0
  91. package/src/index.ts +299 -0
  92. package/src/ipc/ipc-server.ts +207 -0
  93. package/src/jsonrpc/mail-server.ts +356 -0
  94. package/src/map/map-client.ts +260 -0
  95. package/src/mcp/mcp-server.ts +272 -0
  96. package/src/push/notifier.ts +192 -0
  97. package/src/registry/warm-registry.ts +210 -0
  98. package/src/router/message-router.ts +175 -0
  99. package/src/storage/interface.ts +48 -0
  100. package/src/storage/memory.ts +145 -0
  101. package/src/storage/sqlite.ts +645 -0
  102. package/src/traceability/traceability.ts +183 -0
  103. package/src/types.ts +297 -0
  104. package/test/federation/address.test.ts +101 -0
  105. package/test/federation/connection-manager.test.ts +546 -0
  106. package/test/federation/delivery-queue.test.ts +159 -0
  107. package/test/federation/integration.test.ts +823 -0
  108. package/test/federation/routing-engine.test.ts +117 -0
  109. package/test/federation/sdk-integration.test.ts +748 -0
  110. package/test/federation/trust.test.ts +89 -0
  111. package/test/ipc-jsonrpc.test.ts +113 -0
  112. package/test/ipc-server.test.ts +197 -0
  113. package/test/mail-server.test.ts +208 -0
  114. package/test/map-client.test.ts +408 -0
  115. package/test/message-router.test.ts +184 -0
  116. package/test/push-notifier.test.ts +139 -0
  117. package/test/registry/warm-registry.test.ts +171 -0
  118. package/test/sqlite-storage.test.ts +243 -0
  119. package/test/storage.test.ts +196 -0
  120. package/test/traceability.test.ts +123 -0
  121. package/tsconfig.json +20 -0
  122. package/tsup.config.ts +10 -0
  123. package/vitest.config.ts +8 -0
  124. package/dist/index.d.mts +0 -2
  125. package/dist/index.mjs +0 -1
  126. package/dist/index.mjs.map +0 -1
@@ -0,0 +1,69 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * SessionStart hook — auto-registers the agent with Agent Inbox
5
+ * so it can receive messages immediately.
6
+ *
7
+ * Connects to the Agent Inbox IPC socket and sends a register_agent
8
+ * request. If the socket isn't running, silently continues.
9
+ *
10
+ * Setup (in .claude/settings.json or ~/.claude/settings.json):
11
+ *
12
+ * {
13
+ * "hooks": {
14
+ * "SessionStart": [{
15
+ * "hooks": [{
16
+ * "type": "command",
17
+ * "command": "node /path/to/agent-inbox/hooks/register-hook.mjs"
18
+ * }]
19
+ * }]
20
+ * }
21
+ * }
22
+ *
23
+ * Environment:
24
+ * INBOX_AGENT_ID — Agent ID to register (required)
25
+ * INBOX_AGENT_NAME — Display name (optional, defaults to agent ID)
26
+ * INBOX_SOCKET — IPC socket path
27
+ * (default: ~/.cache/agent-inbox/inbox.sock)
28
+ */
29
+
30
+ import * as net from "node:net";
31
+ import * as path from "node:path";
32
+ import * as os from "node:os";
33
+
34
+ const agentId = process.env.INBOX_AGENT_ID;
35
+ if (!agentId) {
36
+ process.exit(0);
37
+ }
38
+
39
+ const agentName = process.env.INBOX_AGENT_NAME || agentId;
40
+ const socketPath =
41
+ process.env.INBOX_SOCKET ||
42
+ path.join(os.homedir(), ".cache", "agent-inbox", "inbox.sock");
43
+
44
+ const request = JSON.stringify({
45
+ action: "register_agent",
46
+ agentId,
47
+ name: agentName,
48
+ program: "claude-code",
49
+ }) + "\n";
50
+
51
+ const client = net.createConnection(socketPath, () => {
52
+ client.write(request);
53
+ // Read one response then close
54
+ client.once("data", () => {
55
+ client.end();
56
+ process.exit(0);
57
+ });
58
+ });
59
+
60
+ // Best-effort — if socket doesn't exist, just continue
61
+ client.on("error", () => {
62
+ process.exit(0);
63
+ });
64
+
65
+ // Timeout after 2 seconds
66
+ setTimeout(() => {
67
+ client.destroy();
68
+ process.exit(0);
69
+ }, 2000);
package/package.json CHANGED
@@ -1,30 +1,21 @@
1
1
  {
2
2
  "name": "agent-inbox",
3
- "version": "0.0.1",
4
- "description": "Agent inbox",
3
+ "version": "0.1.2",
4
+ "description": "Agent Inbox — message routing, traceability, and MCP tools for multi-agent systems",
5
+ "type": "module",
5
6
  "main": "dist/index.js",
6
- "module": "dist/index.mjs",
7
7
  "types": "dist/index.d.ts",
8
- "exports": {
9
- ".": {
10
- "import": {
11
- "types": "./dist/index.d.mts",
12
- "default": "./dist/index.mjs"
13
- },
14
- "require": {
15
- "types": "./dist/index.d.ts",
16
- "default": "./dist/index.js"
17
- }
18
- }
19
- },
20
- "files": [
21
- "dist"
22
- ],
23
8
  "scripts": {
24
- "build": "tsup",
25
- "dev": "tsup --watch",
26
- "test": "echo \"Error: no test specified\" && exit 1",
27
- "prepublishOnly": "npm run build"
9
+ "build": "tsc",
10
+ "dev": "tsc --watch",
11
+ "test": "vitest run",
12
+ "test:watch": "vitest",
13
+ "start": "node dist/index.js",
14
+ "publish:npm": "npm publish --access public",
15
+ "prepublishOnly": "npm run build",
16
+ "version:patch": "npm version patch && git push && git push --tags",
17
+ "version:minor": "npm version minor && git push && git push --tags",
18
+ "version:major": "npm version major && git push && git push --tags"
28
19
  },
29
20
  "repository": {
30
21
  "type": "git",
@@ -37,9 +28,26 @@
37
28
  "url": "https://github.com/alexngai/agent-inbox/issues"
38
29
  },
39
30
  "homepage": "https://github.com/alexngai/agent-inbox#readme",
31
+ "engines": {
32
+ "node": ">=18.0.0"
33
+ },
34
+ "dependencies": {
35
+ "@modelcontextprotocol/sdk": "^1.12.1",
36
+ "better-sqlite3": "^12.6.2",
37
+ "ulid": "^2.3.0"
38
+ },
39
+ "peerDependencies": {
40
+ "@multi-agent-protocol/sdk": "*"
41
+ },
42
+ "peerDependenciesMeta": {
43
+ "@multi-agent-protocol/sdk": {
44
+ "optional": true
45
+ }
46
+ },
40
47
  "devDependencies": {
41
- "@types/node": "^25.3.5",
42
- "tsup": "^8.0.0",
43
- "typescript": "^5.9.3"
48
+ "@types/better-sqlite3": "^7.6.13",
49
+ "@types/node": "^22.0.0",
50
+ "typescript": "^5.7.0",
51
+ "vitest": "^3.0.0"
44
52
  }
45
53
  }
@@ -0,0 +1,78 @@
1
+ # Agent Inbox — Messaging Rules
2
+
3
+ You have access to a message inbox for communicating with other agents.
4
+ Messages may be injected into your context automatically, or you can check manually.
5
+
6
+ ## Tools
7
+
8
+ You have 4 messaging tools: `send_message`, `check_inbox`, `read_thread`, `list_agents`.
9
+
10
+ ## Sending messages
11
+
12
+ Use `send_message` to send a message or reply:
13
+
14
+ ```
15
+ send_message({ to: "alice", body: "Task complete, results in /tmp/output.json" })
16
+ ```
17
+
18
+ To reply to a specific message, include `inReplyTo`:
19
+
20
+ ```
21
+ send_message({ to: "alice", body: "Acknowledged, proceeding.", inReplyTo: "msg-id-here" })
22
+ ```
23
+
24
+ **Parameters:**
25
+ - `to` (required) — Recipient agent ID, or array of IDs. Use `"agent@system"` for federated agents.
26
+ - `body` — Plain text message (shorthand for content)
27
+ - `from` — Your agent ID (set automatically if registered)
28
+ - `subject` — Short subject line
29
+ - `threadTag` — Group related messages under a tag (e.g. `"deploy-v2"`)
30
+ - `inReplyTo` — Message ID you're replying to
31
+ - `importance` — `"low"`, `"normal"` (default), `"high"`, or `"urgent"`
32
+
33
+ ## Checking your inbox
34
+
35
+ Use `check_inbox` to pull messages addressed to you:
36
+
37
+ ```
38
+ check_inbox({ agentId: "your-agent-id" })
39
+ ```
40
+
41
+ If inbox messages are injected automatically (via hook), they appear as a block like:
42
+
43
+ ```
44
+ ## [Inbox] 2 new message(s)
45
+
46
+ **From alice** (5m ago) [high] — Deploy status
47
+ > Cluster is healthy, ready for rollout
48
+ ```
49
+
50
+ ## Threads
51
+
52
+ Use `threadTag` to group related messages. Read an entire thread with:
53
+
54
+ ```
55
+ read_thread({ threadTag: "deploy-v2" })
56
+ ```
57
+
58
+ ## Addressing
59
+
60
+ - `"bob"` — local agent on this system
61
+ - `"bob@system-2"` — agent on a federated remote system
62
+ - `"@system-2"` — broadcast to all agents on a remote system
63
+
64
+ ## Discovering other agents
65
+
66
+ Use `list_agents` to see who's available:
67
+
68
+ ```
69
+ list_agents({})
70
+ list_agents({ includeFederated: true })
71
+ ```
72
+
73
+ ## Conventions
74
+
75
+ - Reply to messages promptly so senders know you received them
76
+ - Use `importance: "high"` or `"urgent"` sparingly — only for time-sensitive coordination
77
+ - Use threads (`threadTag`) for multi-step workflows so context stays grouped
78
+ - Keep messages concise — other agents have limited context windows too
@@ -0,0 +1,61 @@
1
+ import type { FederatedAddress } from "../types.js";
2
+
3
+ /**
4
+ * Parse a federated address string into its components.
5
+ *
6
+ * Formats:
7
+ * "agent-id" → { agent: "agent-id" } (local)
8
+ * "agent-id@system-id" → { agent: "agent-id", system: "system-id" } (federated)
9
+ * "@system-id" → { system: "system-id" } (broadcast to system)
10
+ * "agent-id@system/scope" → { agent: "agent-id", system: "system", scope: "scope" }
11
+ */
12
+ export function parseAddress(address: string): FederatedAddress {
13
+ const atIdx = address.indexOf("@");
14
+ if (atIdx === -1) {
15
+ // No @ — local address
16
+ return { agent: address };
17
+ }
18
+
19
+ const agent = atIdx > 0 ? address.slice(0, atIdx) : undefined;
20
+ const rest = address.slice(atIdx + 1);
21
+
22
+ // Check for scope separator (/)
23
+ const slashIdx = rest.indexOf("/");
24
+ if (slashIdx === -1) {
25
+ return { agent, system: rest };
26
+ }
27
+
28
+ return {
29
+ agent,
30
+ system: rest.slice(0, slashIdx),
31
+ scope: rest.slice(slashIdx + 1),
32
+ };
33
+ }
34
+
35
+ /**
36
+ * Serialize a FederatedAddress back to string form.
37
+ */
38
+ export function formatAddress(addr: FederatedAddress): string {
39
+ let result = addr.agent ?? "";
40
+ if (addr.system) {
41
+ result += `@${addr.system}`;
42
+ if (addr.scope) {
43
+ result += `/${addr.scope}`;
44
+ }
45
+ }
46
+ return result;
47
+ }
48
+
49
+ /**
50
+ * Check if an address targets a remote system.
51
+ */
52
+ export function isRemoteAddress(addr: FederatedAddress): boolean {
53
+ return addr.system !== undefined;
54
+ }
55
+
56
+ /**
57
+ * Check if an address is a broadcast (no specific agent).
58
+ */
59
+ export function isBroadcastAddress(addr: FederatedAddress): boolean {
60
+ return addr.system !== undefined && addr.agent === undefined;
61
+ }