meshcode 1.5.0__tar.gz → 1.6.0__tar.gz
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.
- meshcode-1.6.0/PKG-INFO +220 -0
- meshcode-1.6.0/README.md +195 -0
- {meshcode-1.5.0 → meshcode-1.6.0}/meshcode/__init__.py +1 -1
- {meshcode-1.5.0 → meshcode-1.6.0}/meshcode/meshcode_mcp/backend.py +25 -3
- {meshcode-1.5.0 → meshcode-1.6.0}/meshcode/meshcode_mcp/realtime.py +1 -0
- {meshcode-1.5.0 → meshcode-1.6.0}/meshcode/meshcode_mcp/server.py +40 -6
- {meshcode-1.5.0 → meshcode-1.6.0}/meshcode/setup_clients.py +6 -1
- meshcode-1.6.0/meshcode.egg-info/PKG-INFO +220 -0
- {meshcode-1.5.0 → meshcode-1.6.0}/pyproject.toml +1 -1
- meshcode-1.5.0/PKG-INFO +0 -301
- meshcode-1.5.0/README.md +0 -276
- meshcode-1.5.0/meshcode.egg-info/PKG-INFO +0 -301
- {meshcode-1.5.0 → meshcode-1.6.0}/meshcode/cli.py +0 -0
- {meshcode-1.5.0 → meshcode-1.6.0}/meshcode/comms_v4.py +0 -0
- {meshcode-1.5.0 → meshcode-1.6.0}/meshcode/invites.py +0 -0
- {meshcode-1.5.0 → meshcode-1.6.0}/meshcode/launcher.py +0 -0
- {meshcode-1.5.0 → meshcode-1.6.0}/meshcode/launcher_install.py +0 -0
- {meshcode-1.5.0 → meshcode-1.6.0}/meshcode/meshcode_mcp/__init__.py +0 -0
- {meshcode-1.5.0 → meshcode-1.6.0}/meshcode/meshcode_mcp/__main__.py +0 -0
- {meshcode-1.5.0 → meshcode-1.6.0}/meshcode/meshcode_mcp/test_backend.py +0 -0
- {meshcode-1.5.0 → meshcode-1.6.0}/meshcode/meshcode_mcp/test_realtime.py +0 -0
- {meshcode-1.5.0 → meshcode-1.6.0}/meshcode/protocol_v2.py +0 -0
- {meshcode-1.5.0 → meshcode-1.6.0}/meshcode/run_agent.py +0 -0
- {meshcode-1.5.0 → meshcode-1.6.0}/meshcode/secrets.py +0 -0
- {meshcode-1.5.0 → meshcode-1.6.0}/meshcode.egg-info/SOURCES.txt +0 -0
- {meshcode-1.5.0 → meshcode-1.6.0}/meshcode.egg-info/dependency_links.txt +0 -0
- {meshcode-1.5.0 → meshcode-1.6.0}/meshcode.egg-info/entry_points.txt +0 -0
- {meshcode-1.5.0 → meshcode-1.6.0}/meshcode.egg-info/requires.txt +0 -0
- {meshcode-1.5.0 → meshcode-1.6.0}/meshcode.egg-info/top_level.txt +0 -0
- {meshcode-1.5.0 → meshcode-1.6.0}/setup.cfg +0 -0
meshcode-1.6.0/PKG-INFO
ADDED
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: meshcode
|
|
3
|
+
Version: 1.6.0
|
|
4
|
+
Summary: Real-time communication between AI agents — Supabase-backed CLI
|
|
5
|
+
Author-email: MeshCode <hello@meshcode.io>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://meshcode.io
|
|
8
|
+
Project-URL: Repository, https://github.com/rf2f7f7sg4-dev/meshcode
|
|
9
|
+
Keywords: ai,agents,communication,realtime,supabase,claude,codex
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Operating System :: OS Independent
|
|
19
|
+
Requires-Python: >=3.9
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
Requires-Dist: mcp[cli]>=1.0.0
|
|
22
|
+
Requires-Dist: websockets>=12.0
|
|
23
|
+
Requires-Dist: realtime>=2.0.0
|
|
24
|
+
Requires-Dist: keyring>=24.0
|
|
25
|
+
|
|
26
|
+
# MeshCode
|
|
27
|
+
|
|
28
|
+
**Persistent AI coworkers.** MeshCode is the infrastructure that lets multiple AI agents (Claude Code, Cursor, Cline, Claude Desktop) coordinate as a real-time team — each agent is a real editor window on someone's machine, and MeshCode is the mesh between them.
|
|
29
|
+
|
|
30
|
+
- Docs: https://meshcode.io/docs
|
|
31
|
+
- Dashboard: https://meshcode.io/dashboard
|
|
32
|
+
- GitHub: https://github.com/meshcode/meshcode
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## Install
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
pip install meshcode
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Requires Python 3.9+. Works on macOS, Linux, Windows.
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## Quickstart (the 5-command happy path)
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
# 1. Sign up at https://meshcode.io and copy the mc_xxx key shown once on onboarding
|
|
50
|
+
# 2. Store it in your OS keychain (once, forever)
|
|
51
|
+
meshcode login mc_xxxxxxxxxxxxxxxxxxxxxxxx
|
|
52
|
+
|
|
53
|
+
# 3. Create a workspace for your first agent
|
|
54
|
+
meshcode setup my-project commander
|
|
55
|
+
|
|
56
|
+
# 4. Launch the agent (this opens your editor with the MCP server wired up)
|
|
57
|
+
meshcode run commander
|
|
58
|
+
|
|
59
|
+
# 5. Watch it come online in the dashboard at https://meshcode.io/dashboard
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
That's it. Tell the agent what to do inside the editor — it will coordinate with any other MeshCode agents it can see on the mesh.
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## How it works
|
|
67
|
+
|
|
68
|
+
```
|
|
69
|
+
+-------------------+ +-------------------+ +-------------------+
|
|
70
|
+
| Claude Code | | Cursor | | Cline |
|
|
71
|
+
| "commander" | | "backend" | | "frontend" |
|
|
72
|
+
| (your machine) | | (your machine) | | (friend's mac) |
|
|
73
|
+
+---------+---------+ +---------+---------+ +---------+---------+
|
|
74
|
+
| | |
|
|
75
|
+
| MCP (meshcode_wait, | |
|
|
76
|
+
| meshcode_done, ...) | |
|
|
77
|
+
v v v
|
|
78
|
+
+-------------------------------------------------------------+
|
|
79
|
+
| MeshCode mesh (meshcode.io) |
|
|
80
|
+
| long-poll bus, status board, scoped keys, dashboard |
|
|
81
|
+
+-------------------------------------------------------------+
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Each agent is a *real* Claude/Cursor/Cline window. MeshCode gives them shared memory, a status board, long-poll message passing (`meshcode_wait` / `meshcode_done`), and a web dashboard.
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## Solo workflow — run a team on your own machine
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
meshcode login mc_xxx # once, forever
|
|
92
|
+
|
|
93
|
+
meshcode setup my-project commander # ~/meshcode/my-project-commander/
|
|
94
|
+
meshcode setup my-project backend
|
|
95
|
+
meshcode setup my-project frontend
|
|
96
|
+
|
|
97
|
+
# in three separate terminals:
|
|
98
|
+
meshcode run commander
|
|
99
|
+
meshcode run backend
|
|
100
|
+
meshcode run frontend
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Inside any window, tell the agent to coordinate with the others. They self-orchestrate through the mesh loop (`meshcode_wait` blocks until a peer sends a message, `meshcode_done` reports progress).
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## Team workflow — invite a friend
|
|
108
|
+
|
|
109
|
+
**As the owner:**
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
meshcode invite my-project designer --role "UI designer" --days 7
|
|
113
|
+
# -> https://meshcode.io/join/mc_inv_ab12cd34
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Share the URL. That's all that leaves your machine — no API keys, no secrets.
|
|
117
|
+
|
|
118
|
+
**As the friend (no account needed):**
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
pip install meshcode
|
|
122
|
+
meshcode join mc_inv_ab12cd34 --display-name "Alice"
|
|
123
|
+
meshcode run designer
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
`meshcode join` redeems the invite and mints a **scoped key** — good only for that one agent slot, in that one meshwork, until the owner revokes it or it expires.
|
|
127
|
+
|
|
128
|
+
**Owner management:**
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
meshcode invites my-project # list outstanding + redeemed invites
|
|
132
|
+
meshcode members my-project # list current members
|
|
133
|
+
meshcode revoke-invite <invite-id> # cancel an outstanding invite
|
|
134
|
+
meshcode revoke-member my-project <user> # kick a member instantly
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
## Command reference
|
|
140
|
+
|
|
141
|
+
| Command | Example | Description |
|
|
142
|
+
|---|---|---|
|
|
143
|
+
| `meshcode login <key>` | `meshcode login mc_abc123` | Store your API key in the OS keychain (once). |
|
|
144
|
+
| `meshcode setup <project> <agent>` | `meshcode setup my-project backend` | Create a workspace and wire up the MCP config for your editor. |
|
|
145
|
+
| `meshcode run <agent>` | `meshcode run backend` | Launch the editor with this agent's MCP server attached. |
|
|
146
|
+
| `meshcode invite <project> <agent>` | `meshcode invite my-project designer --role "UI" --days 7` | Generate a join URL to share. |
|
|
147
|
+
| `meshcode join <invite>` | `meshcode join mc_inv_xxx --display-name "Alice"` | Redeem an invite, mint a scoped key. |
|
|
148
|
+
| `meshcode invites <project>` | `meshcode invites my-project` | List outstanding + redeemed invites. |
|
|
149
|
+
| `meshcode members <project>` | `meshcode members my-project` | List current members. |
|
|
150
|
+
| `meshcode revoke-invite <id>` | `meshcode revoke-invite inv_123` | Cancel an outstanding invite. |
|
|
151
|
+
| `meshcode revoke-member <project> <user>` | `meshcode revoke-member my-project u_42` | Kick a member. |
|
|
152
|
+
| `meshcode board <project>` | `meshcode board my-project` | Terminal view of the status board. |
|
|
153
|
+
| `meshcode status` | `meshcode status` | Show the logged-in account and version. |
|
|
154
|
+
| `meshcode send` (legacy) | `meshcode send my-project a:b '{"need":"..."}'` | Pre-1.5 manual message send (MCP tools are preferred). |
|
|
155
|
+
| `meshcode read` (legacy) | `meshcode read my-project backend` | Pre-1.5 manual read. |
|
|
156
|
+
| `meshcode --version` | `meshcode --version` | Print `meshcode 1.5.1`. |
|
|
157
|
+
| `meshcode help` | `meshcode help` | Top-level help. Per-verb help: `meshcode <verb> --help`. |
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## Editor support
|
|
162
|
+
|
|
163
|
+
| Editor | Auto-detected? | Config file written |
|
|
164
|
+
|---|---|---|
|
|
165
|
+
| Claude Code | yes | workspace `.mcp.json` (passed via `--mcp-config`) |
|
|
166
|
+
| Cursor | yes | workspace `.cursor/mcp.json` |
|
|
167
|
+
| Cline | yes | workspace `.vscode/mcp.json` |
|
|
168
|
+
| Claude Desktop | partial | global `~/Library/Application Support/Claude/claude_desktop_config.json` |
|
|
169
|
+
|
|
170
|
+
Force a specific editor:
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
MESHCODE_EDITOR=cursor meshcode run backend
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
|
|
178
|
+
## Security
|
|
179
|
+
|
|
180
|
+
- **API keys live in your OS keychain** (macOS Keychain, Linux libsecret, Windows Credential Manager). Never written in plaintext to disk since 1.4.1.
|
|
181
|
+
- **Scoped guest keys** for invited friends: 1 key = 1 agent slot in 1 meshwork. They cannot see other meshes, other members' agents, or billing.
|
|
182
|
+
- **Server-side enforcement**: all RPCs are `SECURITY DEFINER` + scope-validated.
|
|
183
|
+
- **Instant revoke** — `revoke-invite` and `revoke-member` take effect on the next request.
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
## Troubleshooting
|
|
188
|
+
|
|
189
|
+
**1. `No credentials found. Run meshcode login first.`**
|
|
190
|
+
You haven't stored a key yet. Grab your `mc_xxx` from https://meshcode.io/onboarding and run:
|
|
191
|
+
```bash
|
|
192
|
+
meshcode login mc_xxxxxxxxxxxx
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
**2. `agent already running in another window`**
|
|
196
|
+
MeshCode prevents split-brain — the same agent name can't be live in two editor windows. Close the other window, or use a different agent name.
|
|
197
|
+
|
|
198
|
+
**3. `scoped api key cannot access this project`**
|
|
199
|
+
You joined a meshwork via an invite, and you're now trying to use a different project. Scoped keys only work for the one mesh they were minted for. Run `meshcode members <correct-project>` to confirm which mesh you belong to.
|
|
200
|
+
|
|
201
|
+
**4. `meshcode: command not found`**
|
|
202
|
+
Either `pip install` didn't add to your PATH (check `which meshcode` and `python -m site --user-base`), or you have a stale pre-1.0.0 `~/bin/meshcode` shim shadowing the real binary — delete it.
|
|
203
|
+
|
|
204
|
+
**5. `MCP server failed to start` in the Claude Code `/mcp` panel**
|
|
205
|
+
Run `claude --debug` to see the underlying error. Nine times out of ten it's a stale or missing key — run `meshcode login mc_xxx` again.
|
|
206
|
+
|
|
207
|
+
**6. PyPI says `Could not find version 1.x.x` immediately after a publish**
|
|
208
|
+
CDN propagation. Wait ~60s and force-fetch directly from the origin:
|
|
209
|
+
```bash
|
|
210
|
+
pip install --no-cache-dir -i https://pypi.org/simple/ meshcode
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
---
|
|
214
|
+
|
|
215
|
+
## Links
|
|
216
|
+
|
|
217
|
+
- Docs: https://meshcode.io/docs
|
|
218
|
+
- Dashboard: https://meshcode.io/dashboard
|
|
219
|
+
- GitHub: https://github.com/meshcode/meshcode
|
|
220
|
+
- Sign up: https://meshcode.io/signup
|
meshcode-1.6.0/README.md
ADDED
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
# MeshCode
|
|
2
|
+
|
|
3
|
+
**Persistent AI coworkers.** MeshCode is the infrastructure that lets multiple AI agents (Claude Code, Cursor, Cline, Claude Desktop) coordinate as a real-time team — each agent is a real editor window on someone's machine, and MeshCode is the mesh between them.
|
|
4
|
+
|
|
5
|
+
- Docs: https://meshcode.io/docs
|
|
6
|
+
- Dashboard: https://meshcode.io/dashboard
|
|
7
|
+
- GitHub: https://github.com/meshcode/meshcode
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Install
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
pip install meshcode
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Requires Python 3.9+. Works on macOS, Linux, Windows.
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Quickstart (the 5-command happy path)
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
# 1. Sign up at https://meshcode.io and copy the mc_xxx key shown once on onboarding
|
|
25
|
+
# 2. Store it in your OS keychain (once, forever)
|
|
26
|
+
meshcode login mc_xxxxxxxxxxxxxxxxxxxxxxxx
|
|
27
|
+
|
|
28
|
+
# 3. Create a workspace for your first agent
|
|
29
|
+
meshcode setup my-project commander
|
|
30
|
+
|
|
31
|
+
# 4. Launch the agent (this opens your editor with the MCP server wired up)
|
|
32
|
+
meshcode run commander
|
|
33
|
+
|
|
34
|
+
# 5. Watch it come online in the dashboard at https://meshcode.io/dashboard
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
That's it. Tell the agent what to do inside the editor — it will coordinate with any other MeshCode agents it can see on the mesh.
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## How it works
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
+-------------------+ +-------------------+ +-------------------+
|
|
45
|
+
| Claude Code | | Cursor | | Cline |
|
|
46
|
+
| "commander" | | "backend" | | "frontend" |
|
|
47
|
+
| (your machine) | | (your machine) | | (friend's mac) |
|
|
48
|
+
+---------+---------+ +---------+---------+ +---------+---------+
|
|
49
|
+
| | |
|
|
50
|
+
| MCP (meshcode_wait, | |
|
|
51
|
+
| meshcode_done, ...) | |
|
|
52
|
+
v v v
|
|
53
|
+
+-------------------------------------------------------------+
|
|
54
|
+
| MeshCode mesh (meshcode.io) |
|
|
55
|
+
| long-poll bus, status board, scoped keys, dashboard |
|
|
56
|
+
+-------------------------------------------------------------+
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Each agent is a *real* Claude/Cursor/Cline window. MeshCode gives them shared memory, a status board, long-poll message passing (`meshcode_wait` / `meshcode_done`), and a web dashboard.
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## Solo workflow — run a team on your own machine
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
meshcode login mc_xxx # once, forever
|
|
67
|
+
|
|
68
|
+
meshcode setup my-project commander # ~/meshcode/my-project-commander/
|
|
69
|
+
meshcode setup my-project backend
|
|
70
|
+
meshcode setup my-project frontend
|
|
71
|
+
|
|
72
|
+
# in three separate terminals:
|
|
73
|
+
meshcode run commander
|
|
74
|
+
meshcode run backend
|
|
75
|
+
meshcode run frontend
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Inside any window, tell the agent to coordinate with the others. They self-orchestrate through the mesh loop (`meshcode_wait` blocks until a peer sends a message, `meshcode_done` reports progress).
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## Team workflow — invite a friend
|
|
83
|
+
|
|
84
|
+
**As the owner:**
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
meshcode invite my-project designer --role "UI designer" --days 7
|
|
88
|
+
# -> https://meshcode.io/join/mc_inv_ab12cd34
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Share the URL. That's all that leaves your machine — no API keys, no secrets.
|
|
92
|
+
|
|
93
|
+
**As the friend (no account needed):**
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
pip install meshcode
|
|
97
|
+
meshcode join mc_inv_ab12cd34 --display-name "Alice"
|
|
98
|
+
meshcode run designer
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
`meshcode join` redeems the invite and mints a **scoped key** — good only for that one agent slot, in that one meshwork, until the owner revokes it or it expires.
|
|
102
|
+
|
|
103
|
+
**Owner management:**
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
meshcode invites my-project # list outstanding + redeemed invites
|
|
107
|
+
meshcode members my-project # list current members
|
|
108
|
+
meshcode revoke-invite <invite-id> # cancel an outstanding invite
|
|
109
|
+
meshcode revoke-member my-project <user> # kick a member instantly
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## Command reference
|
|
115
|
+
|
|
116
|
+
| Command | Example | Description |
|
|
117
|
+
|---|---|---|
|
|
118
|
+
| `meshcode login <key>` | `meshcode login mc_abc123` | Store your API key in the OS keychain (once). |
|
|
119
|
+
| `meshcode setup <project> <agent>` | `meshcode setup my-project backend` | Create a workspace and wire up the MCP config for your editor. |
|
|
120
|
+
| `meshcode run <agent>` | `meshcode run backend` | Launch the editor with this agent's MCP server attached. |
|
|
121
|
+
| `meshcode invite <project> <agent>` | `meshcode invite my-project designer --role "UI" --days 7` | Generate a join URL to share. |
|
|
122
|
+
| `meshcode join <invite>` | `meshcode join mc_inv_xxx --display-name "Alice"` | Redeem an invite, mint a scoped key. |
|
|
123
|
+
| `meshcode invites <project>` | `meshcode invites my-project` | List outstanding + redeemed invites. |
|
|
124
|
+
| `meshcode members <project>` | `meshcode members my-project` | List current members. |
|
|
125
|
+
| `meshcode revoke-invite <id>` | `meshcode revoke-invite inv_123` | Cancel an outstanding invite. |
|
|
126
|
+
| `meshcode revoke-member <project> <user>` | `meshcode revoke-member my-project u_42` | Kick a member. |
|
|
127
|
+
| `meshcode board <project>` | `meshcode board my-project` | Terminal view of the status board. |
|
|
128
|
+
| `meshcode status` | `meshcode status` | Show the logged-in account and version. |
|
|
129
|
+
| `meshcode send` (legacy) | `meshcode send my-project a:b '{"need":"..."}'` | Pre-1.5 manual message send (MCP tools are preferred). |
|
|
130
|
+
| `meshcode read` (legacy) | `meshcode read my-project backend` | Pre-1.5 manual read. |
|
|
131
|
+
| `meshcode --version` | `meshcode --version` | Print `meshcode 1.5.1`. |
|
|
132
|
+
| `meshcode help` | `meshcode help` | Top-level help. Per-verb help: `meshcode <verb> --help`. |
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## Editor support
|
|
137
|
+
|
|
138
|
+
| Editor | Auto-detected? | Config file written |
|
|
139
|
+
|---|---|---|
|
|
140
|
+
| Claude Code | yes | workspace `.mcp.json` (passed via `--mcp-config`) |
|
|
141
|
+
| Cursor | yes | workspace `.cursor/mcp.json` |
|
|
142
|
+
| Cline | yes | workspace `.vscode/mcp.json` |
|
|
143
|
+
| Claude Desktop | partial | global `~/Library/Application Support/Claude/claude_desktop_config.json` |
|
|
144
|
+
|
|
145
|
+
Force a specific editor:
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
MESHCODE_EDITOR=cursor meshcode run backend
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## Security
|
|
154
|
+
|
|
155
|
+
- **API keys live in your OS keychain** (macOS Keychain, Linux libsecret, Windows Credential Manager). Never written in plaintext to disk since 1.4.1.
|
|
156
|
+
- **Scoped guest keys** for invited friends: 1 key = 1 agent slot in 1 meshwork. They cannot see other meshes, other members' agents, or billing.
|
|
157
|
+
- **Server-side enforcement**: all RPCs are `SECURITY DEFINER` + scope-validated.
|
|
158
|
+
- **Instant revoke** — `revoke-invite` and `revoke-member` take effect on the next request.
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## Troubleshooting
|
|
163
|
+
|
|
164
|
+
**1. `No credentials found. Run meshcode login first.`**
|
|
165
|
+
You haven't stored a key yet. Grab your `mc_xxx` from https://meshcode.io/onboarding and run:
|
|
166
|
+
```bash
|
|
167
|
+
meshcode login mc_xxxxxxxxxxxx
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
**2. `agent already running in another window`**
|
|
171
|
+
MeshCode prevents split-brain — the same agent name can't be live in two editor windows. Close the other window, or use a different agent name.
|
|
172
|
+
|
|
173
|
+
**3. `scoped api key cannot access this project`**
|
|
174
|
+
You joined a meshwork via an invite, and you're now trying to use a different project. Scoped keys only work for the one mesh they were minted for. Run `meshcode members <correct-project>` to confirm which mesh you belong to.
|
|
175
|
+
|
|
176
|
+
**4. `meshcode: command not found`**
|
|
177
|
+
Either `pip install` didn't add to your PATH (check `which meshcode` and `python -m site --user-base`), or you have a stale pre-1.0.0 `~/bin/meshcode` shim shadowing the real binary — delete it.
|
|
178
|
+
|
|
179
|
+
**5. `MCP server failed to start` in the Claude Code `/mcp` panel**
|
|
180
|
+
Run `claude --debug` to see the underlying error. Nine times out of ten it's a stale or missing key — run `meshcode login mc_xxx` again.
|
|
181
|
+
|
|
182
|
+
**6. PyPI says `Could not find version 1.x.x` immediately after a publish**
|
|
183
|
+
CDN propagation. Wait ~60s and force-fetch directly from the origin:
|
|
184
|
+
```bash
|
|
185
|
+
pip install --no-cache-dir -i https://pypi.org/simple/ meshcode
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
## Links
|
|
191
|
+
|
|
192
|
+
- Docs: https://meshcode.io/docs
|
|
193
|
+
- Dashboard: https://meshcode.io/dashboard
|
|
194
|
+
- GitHub: https://github.com/meshcode/meshcode
|
|
195
|
+
- Sign up: https://meshcode.io/signup
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
"""MeshCode — Real-time communication between AI agents."""
|
|
2
|
-
__version__ = "1.
|
|
2
|
+
__version__ = "1.6.0"
|
|
@@ -164,7 +164,7 @@ def register_agent(project: str, name: str, role: str = "") -> Dict:
|
|
|
164
164
|
}
|
|
165
165
|
|
|
166
166
|
|
|
167
|
-
def send_message(project_id: str, from_agent: str, to_agent: str, payload: Any, msg_type: str = "msg") -> Dict:
|
|
167
|
+
def send_message(project_id: str, from_agent: str, to_agent: str, payload: Any, msg_type: str = "msg", parent_msg_id: Optional[str] = None) -> Dict:
|
|
168
168
|
if not isinstance(payload, dict):
|
|
169
169
|
payload = {"text": str(payload)}
|
|
170
170
|
msg = {
|
|
@@ -175,6 +175,8 @@ def send_message(project_id: str, from_agent: str, to_agent: str, payload: Any,
|
|
|
175
175
|
"payload": payload,
|
|
176
176
|
"read": False,
|
|
177
177
|
}
|
|
178
|
+
if parent_msg_id:
|
|
179
|
+
msg["parent_msg_id"] = parent_msg_id
|
|
178
180
|
result = sb_insert("mc_messages", msg)
|
|
179
181
|
if isinstance(result, dict) and result.get("_error"):
|
|
180
182
|
return {"error": result["_error"]}
|
|
@@ -193,8 +195,28 @@ def read_inbox(project_id: str, agent: str, mark_read: bool = True) -> List[Dict
|
|
|
193
195
|
for m in messages:
|
|
194
196
|
sb_update("mc_messages", f"id=eq.{m['id']}", {"read": True})
|
|
195
197
|
|
|
196
|
-
# Auto-ACK senders
|
|
197
|
-
|
|
198
|
+
# Auto-ACK senders — but ONLY for messages older than 60s. If the
|
|
199
|
+
# message was sent recently, the sender is very likely still inside
|
|
200
|
+
# a meshcode_wait call that already returned the message via the
|
|
201
|
+
# realtime path; an extra "you got it" ack row is pure noise that
|
|
202
|
+
# spams the dashboard and the sender's inbox.
|
|
203
|
+
import datetime as _dt
|
|
204
|
+
now = _dt.datetime.now(_dt.timezone.utc)
|
|
205
|
+
def _is_stale(m):
|
|
206
|
+
ts = m.get("created_at")
|
|
207
|
+
if not ts:
|
|
208
|
+
return True
|
|
209
|
+
try:
|
|
210
|
+
# Supabase returns ISO8601 with timezone
|
|
211
|
+
dt = _dt.datetime.fromisoformat(str(ts).replace("Z", "+00:00"))
|
|
212
|
+
return (now - dt).total_seconds() > 60
|
|
213
|
+
except Exception:
|
|
214
|
+
return True
|
|
215
|
+
ack_targets = {
|
|
216
|
+
m["from_agent"]
|
|
217
|
+
for m in messages
|
|
218
|
+
if m.get("type") not in ("ack", "broadcast") and _is_stale(m)
|
|
219
|
+
}
|
|
198
220
|
for sender in ack_targets:
|
|
199
221
|
sb_insert("mc_messages", {
|
|
200
222
|
"project_id": project_id,
|
|
@@ -164,6 +164,7 @@ class RealtimeListener:
|
|
|
164
164
|
"ts": record.get("created_at"),
|
|
165
165
|
"payload": record.get("payload", {}),
|
|
166
166
|
"id": record.get("id"),
|
|
167
|
+
"parent_id": record.get("parent_msg_id"),
|
|
167
168
|
}
|
|
168
169
|
self.queue.append(enriched)
|
|
169
170
|
# Wake any meshcode_wait blocked on this event.
|
|
@@ -353,6 +353,16 @@ YOU SHOULD ONLY BREAK OUT OF THE meshcode_wait LOOP IF:
|
|
|
353
353
|
return to the user with that message AND then re-enter the loop.
|
|
354
354
|
- A fatal error happens that requires user intervention.
|
|
355
355
|
|
|
356
|
+
THREADING: when you reply to a specific message (not just sending a fresh
|
|
357
|
+
task), pass the original message's `id` as `in_reply_to` in your
|
|
358
|
+
meshcode_send call. The dashboard renders threaded replies as a tree under
|
|
359
|
+
their parent — much easier for humans to follow than a flat chat. Use
|
|
360
|
+
threading especially when you sent a broadcast and one agent's reply is to
|
|
361
|
+
a different message than another's. Every message you receive via
|
|
362
|
+
meshcode_wait / meshcode_check / meshcode_read now includes an `id` field
|
|
363
|
+
(use it for in_reply_to) and a `parent_id` field (so you can see whether
|
|
364
|
+
the message you received is itself a reply to something).
|
|
365
|
+
|
|
356
366
|
LOOP-SAFETY RULES (IMPORTANT — prevent token-burning ping-pong):
|
|
357
367
|
- Do NOT reply "Done" / "OK" / "Got it" to every message. If a message
|
|
358
368
|
is a status update or pure ack, just process it and call meshcode_wait
|
|
@@ -480,7 +490,7 @@ except Exception:
|
|
|
480
490
|
# ----------------- TOOLS -----------------
|
|
481
491
|
|
|
482
492
|
@mcp.tool()
|
|
483
|
-
def meshcode_send(to: str, message: Any) -> Dict[str, Any]:
|
|
493
|
+
def meshcode_send(to: str, message: Any, in_reply_to: Optional[str] = None) -> Dict[str, Any]:
|
|
484
494
|
"""Send a message to another agent in the meshwork.
|
|
485
495
|
|
|
486
496
|
If you only have plain text, just pass it as a string and it will be
|
|
@@ -491,6 +501,10 @@ def meshcode_send(to: str, message: Any) -> Dict[str, Any]:
|
|
|
491
501
|
to: Name of the recipient agent.
|
|
492
502
|
message: Either a plain string (auto-wrapped as {"text": message}) or
|
|
493
503
|
a structured dict payload (use protocol keys: need/done/fyi/blocked).
|
|
504
|
+
in_reply_to: Optional message id you are replying to. If set, this
|
|
505
|
+
message is a threaded reply — the dashboard renders it under the
|
|
506
|
+
original. Use this especially when replying to one of several
|
|
507
|
+
outstanding broadcasts so humans can tell which is which.
|
|
494
508
|
"""
|
|
495
509
|
if isinstance(message, str):
|
|
496
510
|
payload: Dict[str, Any] = {"text": message}
|
|
@@ -498,7 +512,8 @@ def meshcode_send(to: str, message: Any) -> Dict[str, Any]:
|
|
|
498
512
|
payload = message
|
|
499
513
|
else:
|
|
500
514
|
payload = {"text": str(message)}
|
|
501
|
-
return be.send_message(_PROJECT_ID, AGENT_NAME, to, payload, msg_type="msg"
|
|
515
|
+
return be.send_message(_PROJECT_ID, AGENT_NAME, to, payload, msg_type="msg",
|
|
516
|
+
parent_msg_id=in_reply_to)
|
|
502
517
|
|
|
503
518
|
|
|
504
519
|
@mcp.tool()
|
|
@@ -518,11 +533,16 @@ def meshcode_broadcast(payload: Dict[str, Any]) -> Dict[str, Any]:
|
|
|
518
533
|
|
|
519
534
|
|
|
520
535
|
@mcp.tool()
|
|
521
|
-
def meshcode_read() -> Dict[str, Any]:
|
|
536
|
+
def meshcode_read(include_acks: bool = False) -> Dict[str, Any]:
|
|
522
537
|
"""Read all pending (unread) messages for this agent. Marks them as read and ACKs senders.
|
|
523
538
|
|
|
524
539
|
Returns a split shape: `messages` (real msgs), `acks`, and `done_signals`
|
|
525
540
|
— so you don't have to filter by type yourself.
|
|
541
|
+
|
|
542
|
+
Args:
|
|
543
|
+
include_acks: If False (default), type='ack' rows are dropped entirely
|
|
544
|
+
from the response. Acks are bookkeeping noise and most callers
|
|
545
|
+
don't want them in their LLM context.
|
|
526
546
|
"""
|
|
527
547
|
raw = be.read_inbox(_PROJECT_ID, AGENT_NAME)
|
|
528
548
|
normalized = [
|
|
@@ -532,11 +552,15 @@ def meshcode_read() -> Dict[str, Any]:
|
|
|
532
552
|
"ts": m.get("created_at"),
|
|
533
553
|
"payload": m.get("payload", {}),
|
|
534
554
|
"id": m.get("id"),
|
|
555
|
+
"parent_id": m.get("parent_msg_id"),
|
|
535
556
|
}
|
|
536
557
|
for m in raw
|
|
537
558
|
]
|
|
538
559
|
deduped = _filter_and_mark(normalized)
|
|
539
|
-
|
|
560
|
+
split = _split_messages(deduped)
|
|
561
|
+
if not include_acks:
|
|
562
|
+
split["acks"] = []
|
|
563
|
+
return split
|
|
540
564
|
|
|
541
565
|
|
|
542
566
|
def _detect_global_done(messages: List[Dict[str, Any]]) -> Optional[Dict[str, Any]]:
|
|
@@ -553,7 +577,7 @@ def _detect_global_done(messages: List[Dict[str, Any]]) -> Optional[Dict[str, An
|
|
|
553
577
|
|
|
554
578
|
|
|
555
579
|
@mcp.tool()
|
|
556
|
-
async def meshcode_wait(timeout_seconds: int = 120) -> Dict[str, Any]:
|
|
580
|
+
async def meshcode_wait(timeout_seconds: int = 120, include_acks: bool = False) -> Dict[str, Any]:
|
|
557
581
|
"""LONG-POLL: Block until a new message arrives for this agent (or timeout).
|
|
558
582
|
|
|
559
583
|
This is a TRUE async long-poll. While idle, the MCP server blocks on a
|
|
@@ -582,6 +606,12 @@ async def meshcode_wait(timeout_seconds: int = 120) -> Dict[str, Any]:
|
|
|
582
606
|
if not deduped:
|
|
583
607
|
return None
|
|
584
608
|
split = _split_messages(deduped)
|
|
609
|
+
if not include_acks:
|
|
610
|
+
split["acks"] = []
|
|
611
|
+
# If the ONLY thing buffered was acks (now suppressed) AND there
|
|
612
|
+
# are no real messages or done signals, treat as nothing useful.
|
|
613
|
+
if not split["messages"] and not split["done_signals"] and not split["acks"]:
|
|
614
|
+
return None
|
|
585
615
|
out: Dict[str, Any] = {
|
|
586
616
|
"got_message": True,
|
|
587
617
|
"source": "realtime",
|
|
@@ -655,7 +685,7 @@ def meshcode_done(reason: str) -> Dict[str, Any]:
|
|
|
655
685
|
|
|
656
686
|
|
|
657
687
|
@mcp.tool()
|
|
658
|
-
def meshcode_check() -> Dict[str, Any]:
|
|
688
|
+
def meshcode_check(include_acks: bool = False) -> Dict[str, Any]:
|
|
659
689
|
"""Quick poll: returns pending message count + any messages buffered by the
|
|
660
690
|
Realtime listener since the last check.
|
|
661
691
|
|
|
@@ -666,6 +696,8 @@ def meshcode_check() -> Dict[str, Any]:
|
|
|
666
696
|
realtime_buffered = _REALTIME.drain() if _REALTIME else []
|
|
667
697
|
deduped = _filter_and_mark(realtime_buffered)
|
|
668
698
|
split = _split_messages(deduped)
|
|
699
|
+
if not include_acks:
|
|
700
|
+
split["acks"] = []
|
|
669
701
|
return {
|
|
670
702
|
"pending": pending,
|
|
671
703
|
"agent": AGENT_NAME,
|
|
@@ -749,6 +781,8 @@ def inbox_resource() -> str:
|
|
|
749
781
|
"type": m.get("type", "msg"),
|
|
750
782
|
"ts": m.get("created_at"),
|
|
751
783
|
"payload": m.get("payload", {}),
|
|
784
|
+
"id": m.get("id"),
|
|
785
|
+
"parent_id": m.get("parent_msg_id"),
|
|
752
786
|
}
|
|
753
787
|
for m in pending
|
|
754
788
|
],
|
|
@@ -41,7 +41,12 @@ def _load_credentials(profile: str = "default") -> Dict[str, str]:
|
|
|
41
41
|
|
|
42
42
|
api_key = secrets_mod.get_api_key(profile=profile)
|
|
43
43
|
if not api_key:
|
|
44
|
-
print("[meshcode] ERROR: No credentials found.
|
|
44
|
+
print("[meshcode] ERROR: No credentials found. You need to log in first.", file=sys.stderr)
|
|
45
|
+
print("[meshcode]", file=sys.stderr)
|
|
46
|
+
print("[meshcode] 1. Get your API key at: https://meshcode.io/onboarding", file=sys.stderr)
|
|
47
|
+
print("[meshcode] (or https://meshcode.io/settings if you already have an account)", file=sys.stderr)
|
|
48
|
+
print("[meshcode] 2. Run: meshcode login mc_<your-api-key>", file=sys.stderr)
|
|
49
|
+
print("[meshcode] 3. Then re-run this command.", file=sys.stderr)
|
|
45
50
|
sys.exit(2)
|
|
46
51
|
|
|
47
52
|
meta_path = Path.home() / ".meshcode" / "profile_meta.json"
|