@manuelfedele/postino 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.
@@ -0,0 +1,21 @@
1
+ {
2
+ "name": "postino",
3
+ "version": "0.1.0",
4
+ "description": "Inter-agent messaging and broadcast system for Claude Code. Send 1-to-1 messages between tabs, broadcast to all agents, with a real-time web GUI.",
5
+ "author": {
6
+ "name": "Manuel Fedele"
7
+ },
8
+ "repository": "https://github.com/manuelfedele/postino",
9
+ "license": "MIT",
10
+ "keywords": [
11
+ "messaging",
12
+ "broadcast",
13
+ "multi-agent",
14
+ "valkey",
15
+ "redis",
16
+ "mcp",
17
+ "inter-process"
18
+ ],
19
+ "mcpServers": "./.mcp.json",
20
+ "hooks": "./hooks/hooks.json"
21
+ }
package/.mcp.json ADDED
@@ -0,0 +1,7 @@
1
+ {
2
+ "postino": {
3
+ "command": "node",
4
+ "args": ["${CLAUDE_PLUGIN_ROOT}/dist/index.js"],
5
+ "env": {}
6
+ }
7
+ }
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 simple-memory contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,216 @@
1
+ <p align="center">
2
+ <picture>
3
+ <source media="(prefers-color-scheme: dark)" srcset="src/web/public/logo-dark.svg">
4
+ <source media="(prefers-color-scheme: light)" srcset="src/web/public/logo-horizontal.svg">
5
+ <img src="src/web/public/logo-horizontal.svg" alt="postino - message broker for agents" width="440">
6
+ </picture>
7
+ </p>
8
+
9
+ <p align="center">
10
+ <strong>Message broker for Claude Code agents</strong>
11
+ </p>
12
+
13
+ <p align="center">
14
+ Working with Claude in multiple tabs and sharing context between agents can be painful.<br>
15
+ Postino (<em>mailman</em> in Italian) gives your agents a way to talk to each other.
16
+ </p>
17
+
18
+ <p align="center">
19
+ <a href="#features">Features</a> &nbsp;&middot;&nbsp;
20
+ <a href="#quick-start">Quick Start</a> &nbsp;&middot;&nbsp;
21
+ <a href="#mcp-tools">Tools</a> &nbsp;&middot;&nbsp;
22
+ <a href="#web-gui">GUI</a> &nbsp;&middot;&nbsp;
23
+ <a href="#how-it-works">How It Works</a> &nbsp;&middot;&nbsp;
24
+ <a href="#configuration">Config</a>
25
+ </p>
26
+
27
+ <p align="center">
28
+ <a href="https://www.npmjs.com/package/@manuelfedele/postino"><img src="https://img.shields.io/npm/v/@manuelfedele/postino?color=e63030" alt="npm"></a>
29
+ <a href="https://github.com/manuelfedele/postino/actions"><img src="https://github.com/manuelfedele/postino/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
30
+ <img src="https://img.shields.io/badge/license-MIT-blue" alt="MIT License">
31
+ <img src="https://img.shields.io/badge/node-%3E%3D18-brightgreen" alt="Node >= 18">
32
+ </p>
33
+
34
+ ---
35
+
36
+ ## Quick Start
37
+
38
+ ```bash
39
+ npx @manuelfedele/postino install
40
+ ```
41
+
42
+ That's it. Restart Claude Code. Your agent is online.
43
+
44
+ > **Prerequisite:** Valkey or Redis running on `localhost:6379`
45
+
46
+ <details>
47
+ <summary>Other install methods</summary>
48
+
49
+ ### From source
50
+
51
+ ```bash
52
+ git clone https://github.com/manuelfedele/postino.git
53
+ cd postino
54
+ npm install && npm run build
55
+ claude mcp add postino -s user -- node $(pwd)/dist/index.js
56
+ ```
57
+
58
+ ### With a named agent
59
+
60
+ ```bash
61
+ claude mcp add postino -s user -e POSTINO_AGENT_NAME=researcher -- npx @manuelfedele/postino
62
+ ```
63
+
64
+ ### Uninstall
65
+
66
+ ```bash
67
+ npx @manuelfedele/postino uninstall
68
+ ```
69
+
70
+ </details>
71
+
72
+ ---
73
+
74
+ ## Features
75
+
76
+ **1-to-1 Messaging** &mdash; Send messages to specific agents. Messages are consumed on read, like a work queue. No duplicates, no stale data.
77
+
78
+ **Broadcasts** &mdash; Announce to all agents at once. Every agent sees broadcasts independently. They expire by TTL, not by reading.
79
+
80
+ **Agent Discovery** &mdash; Agents auto-register with unique identities derived from the terminal session. See who's online, who has unread messages.
81
+
82
+ **Agent Rename** &mdash; Agents can rename themselves to meaningful names like `devops-agent` or `reviewer`. The name propagates instantly.
83
+
84
+ **Real-time Web GUI** &mdash; Browse inboxes, send messages, view broadcasts. Updates live via SSE. Works offline (no CDN dependencies).
85
+
86
+ **Zero Config** &mdash; Each Claude Code tab gets a unique agent name automatically. No setup required beyond having Valkey/Redis running.
87
+
88
+ **Smart Hooks** &mdash; A `UserPromptSubmit` hook checks for new messages before each prompt. Silent when there's nothing new (zero token cost). Alerts Claude when messages arrive.
89
+
90
+ ---
91
+
92
+ ## MCP Tools
93
+
94
+ | Tool | Description |
95
+ |:-----|:------------|
96
+ | `msg_whoami` | Full status overview: identity, unread messages, unseen broadcasts, online agents. Call this first. |
97
+ | `msg_check` | Quick check for new messages and broadcasts without consuming them. |
98
+ | `msg_send` | Send a 1-to-1 message. Consumed when the recipient calls `msg_read`. |
99
+ | `msg_read` | Read and consume messages from your inbox. |
100
+ | `msg_broadcast` | Broadcast to all agents. Not consumed on read, expires by TTL. |
101
+ | `msg_broadcasts` | Read unseen broadcasts. Pass `all=true` to see everything. |
102
+ | `msg_list_agents` | List all agents with online/offline status and message counts. |
103
+ | `msg_rename` | Rename this agent (e.g. `devops-agent`, `code-reviewer`). |
104
+
105
+ ---
106
+
107
+ ## Web GUI
108
+
109
+ The GUI starts automatically alongside the MCP server on port **3333**.
110
+ If the port is in use, it auto-increments (3334, 3335, ...).
111
+
112
+ Open **http://localhost:3333** in your browser.
113
+
114
+ | Tab | What it shows |
115
+ |:----|:--------------|
116
+ | **Messages** | Agent inbox sidebar with online indicators, message threads, compose form |
117
+ | **Broadcasts** | Shared announcement feed, broadcast compose |
118
+
119
+ Updates in real-time via Server-Sent Events. When an agent sends a message from the CLI, the GUI reflects it instantly.
120
+
121
+ ---
122
+
123
+ ## How It Works
124
+
125
+ ```
126
+ Tab 1 (agent-A) Valkey Tab 2 (agent-B)
127
+ | | |
128
+ |-- msg_send(to=B, "do X") ---->| |
129
+ | |-- pub/sub notify ----------->|
130
+ | | |-- msg_check()
131
+ | | | "1 unread message"
132
+ | | |-- msg_read()
133
+ | |<-- consume --------------------| [{from: A, body: "do X"}]
134
+ | | |
135
+ |-- msg_broadcast("deploy") --->|-- shared list -------------->|
136
+ | | |-- msg_broadcasts()
137
+ | | | [{from: A, body: "deploy"}]
138
+ ```
139
+
140
+ **Messages** are Valkey lists (one per agent inbox). `msg_send` pushes, `msg_read` pops. Messages have a 24h TTL as a safety net for unread messages.
141
+
142
+ **Broadcasts** are a shared Valkey list. Each agent tracks a cursor (last-seen index). Reading broadcasts advances the cursor without deleting the data, so every agent sees every broadcast.
143
+
144
+ **Agent presence** uses Valkey keys with a 30-second TTL, refreshed by a heartbeat. If a process dies, it goes offline within 30 seconds.
145
+
146
+ **The hook** (`UserPromptSubmit`) calls `GET /api/check/:agent` via curl. If there are no new messages or broadcasts, it outputs nothing (zero tokens). If there's something new, it injects a one-line hint so Claude knows to check.
147
+
148
+ ---
149
+
150
+ ## Configuration
151
+
152
+ All configuration is via environment variables. Everything has sensible defaults.
153
+
154
+ | Variable | Default | Description |
155
+ |:---------|:--------|:------------|
156
+ | `POSTINO_VALKEY_URL` | `redis://127.0.0.1:6379` | Valkey/Redis connection URL |
157
+ | `POSTINO_WEB_PORT` | `3333` | Web GUI port (auto-increments on collision) |
158
+ | `POSTINO_WEB_ENABLED` | `true` | Set to `false` for MCP-only mode |
159
+ | `POSTINO_AGENT_NAME` | auto-detected | Override agent name (auto-derived from terminal session ID) |
160
+ | `POSTINO_MSG_TTL` | `86400` | Message/broadcast TTL in seconds (24h) |
161
+ | `POSTINO_KEY_PREFIX` | `po:` | Valkey key prefix (change to run multiple instances) |
162
+
163
+ ### Named agents
164
+
165
+ ```bash
166
+ claude mcp add postino -e POSTINO_AGENT_NAME=researcher -- node /path/to/postino/dist/index.js
167
+ ```
168
+
169
+ Or rename at runtime:
170
+
171
+ > "Rename yourself to devops-agent"
172
+
173
+ ---
174
+
175
+ ## Development
176
+
177
+ ```bash
178
+ npm install # Install dependencies
179
+ npm run build # Compile TypeScript + copy static assets
180
+ npm run dev # Watch mode
181
+ npm test # Run test suite (requires Valkey on localhost)
182
+ ```
183
+
184
+ ### Project structure
185
+
186
+ ```
187
+ postino/
188
+ src/
189
+ index.ts # Entry point: MCP server + web server
190
+ types.ts # Config, interfaces
191
+ valkey.ts # Valkey client, agent presence, pub/sub
192
+ tools/
193
+ messaging.ts # All 8 MCP tools
194
+ web/
195
+ server.ts # Hono HTTP server, static files
196
+ api.ts # REST API + SSE
197
+ public/
198
+ index.html # Single-file GUI (no build step, no CDN)
199
+ favicon.svg # Favicon
200
+ logo.svg # Logo sheet
201
+ hooks/
202
+ check-messages.sh # UserPromptSubmit hook (zero-token check)
203
+ hooks.json # Hook configuration
204
+ commands/
205
+ postino.md # /postino slash command
206
+ test/ # Integration tests (vitest)
207
+ .claude-plugin/
208
+ plugin.json # Claude Code plugin manifest
209
+ .mcp.json # MCP server registration
210
+ ```
211
+
212
+ ---
213
+
214
+ ## License
215
+
216
+ MIT
@@ -0,0 +1,20 @@
1
+ ---
2
+ name: postino
3
+ description: Check your postino inbox, list agents, and manage messages
4
+ argument-hint: [check|agents|broadcast <message>]
5
+ allowed-tools: []
6
+ ---
7
+
8
+ # Postino - Inter-agent messaging
9
+
10
+ When the user runs `/postino`, help them with their messaging needs.
11
+
12
+ ## Behavior
13
+
14
+ - `/postino` or `/postino check`: Check your inbox for new messages using `msg_check`, then read them with `msg_read` if any exist.
15
+ - `/postino agents`: List all agents using `msg_list_agents`.
16
+ - `/postino broadcast <message>`: Send a broadcast using `msg_broadcast`.
17
+ - `/postino rename <name>`: Rename this agent using `msg_rename`.
18
+ - `/postino whoami`: Show your agent identity using `msg_whoami`.
19
+
20
+ Always use the postino MCP tools (msg_whoami, msg_check, msg_read, msg_send, msg_broadcast, msg_list_agents, msg_rename, msg_broadcasts) to accomplish these tasks. Do not fabricate responses.
package/dist/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/cli.js ADDED
@@ -0,0 +1,96 @@
1
+ #!/usr/bin/env node
2
+ import { execSync } from "node:child_process";
3
+ import { dirname, join } from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+ const __dirname = dirname(fileURLToPath(import.meta.url));
6
+ const args = process.argv.slice(2);
7
+ const command = args[0];
8
+ function run(cmd) {
9
+ try {
10
+ return execSync(cmd, { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
11
+ }
12
+ catch (e) {
13
+ const err = e;
14
+ return err.stderr?.trim() || err.message || "";
15
+ }
16
+ }
17
+ function hasClaude() {
18
+ const result = run("which claude");
19
+ return result.length > 0 && !result.includes("not found");
20
+ }
21
+ function install() {
22
+ console.log("\n postino - message broker for Claude Code agents\n");
23
+ if (!hasClaude()) {
24
+ console.error(" Error: 'claude' CLI not found. Install Claude Code first:");
25
+ console.error(" https://docs.anthropic.com/en/docs/claude-code\n");
26
+ process.exit(1);
27
+ }
28
+ // Find the MCP server entry point (relative to this CLI script)
29
+ const serverPath = join(__dirname, "index.js");
30
+ // Check if already registered
31
+ const existing = run("claude mcp list 2>&1");
32
+ if (existing.includes("postino")) {
33
+ console.log(" Updating existing postino registration...\n");
34
+ run("claude mcp remove postino -s user 2>&1");
35
+ }
36
+ // Register globally (user scope)
37
+ const result = run(`claude mcp add postino -s user -- node ${serverPath}`);
38
+ if (result.includes("Added")) {
39
+ console.log(" Installed successfully!\n");
40
+ console.log(" Restart Claude Code to activate postino.");
41
+ console.log(" Web GUI will be at http://localhost:3333\n");
42
+ console.log(" Prerequisites:");
43
+ console.log(" - Valkey or Redis running on localhost:6379\n");
44
+ console.log(" To uninstall: npx postino uninstall\n");
45
+ }
46
+ else {
47
+ console.log(" Registration output:", result);
48
+ console.log("\n If this failed, try manually:");
49
+ console.log(` claude mcp add postino -s user -- node ${serverPath}\n`);
50
+ }
51
+ }
52
+ function uninstall() {
53
+ console.log("\n Removing postino...\n");
54
+ if (!hasClaude()) {
55
+ console.error(" Error: 'claude' CLI not found.\n");
56
+ process.exit(1);
57
+ }
58
+ const result = run("claude mcp remove postino -s user 2>&1");
59
+ if (result.includes("Removed") || result.includes("removed")) {
60
+ console.log(" Uninstalled successfully. Restart Claude Code.\n");
61
+ }
62
+ else {
63
+ console.log(" " + (result || "postino was not registered.") + "\n");
64
+ }
65
+ }
66
+ function printHelp() {
67
+ console.log(`
68
+ postino - message broker for Claude Code agents
69
+
70
+ Usage:
71
+ npx postino install Register postino with Claude Code
72
+ npx postino uninstall Remove postino from Claude Code
73
+
74
+ After installing, restart Claude Code. Your agents will have
75
+ access to messaging, broadcasts, and a web GUI.
76
+
77
+ Docs: https://github.com/manuelfedele/postino
78
+ `);
79
+ }
80
+ switch (command) {
81
+ case "install":
82
+ install();
83
+ break;
84
+ case "uninstall":
85
+ uninstall();
86
+ break;
87
+ case "help":
88
+ case "--help":
89
+ case "-h":
90
+ printHelp();
91
+ break;
92
+ default:
93
+ // No CLI command: start the MCP server (normal operation)
94
+ import("./index.js");
95
+ break;
96
+ }
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,38 @@
1
+ #!/usr/bin/env node
2
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
+ import { loadConfig } from "./types.js";
5
+ import { connect, disconnect, registerAgent, deregisterAgent } from "./valkey.js";
6
+ import { registerMessagingTools } from "./tools/messaging.js";
7
+ import { startWebServer } from "./web/server.js";
8
+ const config = loadConfig();
9
+ const server = new McpServer({
10
+ name: "postino",
11
+ version: "0.1.0",
12
+ }, {
13
+ capabilities: {
14
+ tools: {},
15
+ },
16
+ });
17
+ registerMessagingTools(server, config.agentName);
18
+ async function main() {
19
+ await connect();
20
+ await registerAgent(config.agentName);
21
+ const transport = new StdioServerTransport();
22
+ await server.connect(transport);
23
+ if (config.webEnabled) {
24
+ startWebServer(config.webPort);
25
+ }
26
+ process.stderr.write(`postino agent: ${config.agentName}\n`);
27
+ const shutdown = async () => {
28
+ await deregisterAgent(config.agentName);
29
+ await disconnect();
30
+ process.exit(0);
31
+ };
32
+ process.on("SIGINT", shutdown);
33
+ process.on("SIGTERM", shutdown);
34
+ }
35
+ main().catch((err) => {
36
+ console.error("Failed to start postino:", err);
37
+ process.exit(1);
38
+ });
@@ -0,0 +1,2 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerMessagingTools(server: McpServer, initialName: string): void;