meshcode 1.5.1__tar.gz → 1.7.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.
Files changed (30) hide show
  1. meshcode-1.7.0/PKG-INFO +220 -0
  2. meshcode-1.7.0/README.md +195 -0
  3. {meshcode-1.5.1 → meshcode-1.7.0}/meshcode/__init__.py +1 -1
  4. {meshcode-1.5.1 → meshcode-1.7.0}/meshcode/meshcode_mcp/backend.py +66 -3
  5. {meshcode-1.5.1 → meshcode-1.7.0}/meshcode/meshcode_mcp/realtime.py +1 -0
  6. {meshcode-1.5.1 → meshcode-1.7.0}/meshcode/meshcode_mcp/server.py +114 -6
  7. {meshcode-1.5.1 → meshcode-1.7.0}/meshcode/setup_clients.py +6 -1
  8. meshcode-1.7.0/meshcode.egg-info/PKG-INFO +220 -0
  9. {meshcode-1.5.1 → meshcode-1.7.0}/pyproject.toml +1 -1
  10. meshcode-1.5.1/PKG-INFO +0 -301
  11. meshcode-1.5.1/README.md +0 -276
  12. meshcode-1.5.1/meshcode.egg-info/PKG-INFO +0 -301
  13. {meshcode-1.5.1 → meshcode-1.7.0}/meshcode/cli.py +0 -0
  14. {meshcode-1.5.1 → meshcode-1.7.0}/meshcode/comms_v4.py +0 -0
  15. {meshcode-1.5.1 → meshcode-1.7.0}/meshcode/invites.py +0 -0
  16. {meshcode-1.5.1 → meshcode-1.7.0}/meshcode/launcher.py +0 -0
  17. {meshcode-1.5.1 → meshcode-1.7.0}/meshcode/launcher_install.py +0 -0
  18. {meshcode-1.5.1 → meshcode-1.7.0}/meshcode/meshcode_mcp/__init__.py +0 -0
  19. {meshcode-1.5.1 → meshcode-1.7.0}/meshcode/meshcode_mcp/__main__.py +0 -0
  20. {meshcode-1.5.1 → meshcode-1.7.0}/meshcode/meshcode_mcp/test_backend.py +0 -0
  21. {meshcode-1.5.1 → meshcode-1.7.0}/meshcode/meshcode_mcp/test_realtime.py +0 -0
  22. {meshcode-1.5.1 → meshcode-1.7.0}/meshcode/protocol_v2.py +0 -0
  23. {meshcode-1.5.1 → meshcode-1.7.0}/meshcode/run_agent.py +0 -0
  24. {meshcode-1.5.1 → meshcode-1.7.0}/meshcode/secrets.py +0 -0
  25. {meshcode-1.5.1 → meshcode-1.7.0}/meshcode.egg-info/SOURCES.txt +0 -0
  26. {meshcode-1.5.1 → meshcode-1.7.0}/meshcode.egg-info/dependency_links.txt +0 -0
  27. {meshcode-1.5.1 → meshcode-1.7.0}/meshcode.egg-info/entry_points.txt +0 -0
  28. {meshcode-1.5.1 → meshcode-1.7.0}/meshcode.egg-info/requires.txt +0 -0
  29. {meshcode-1.5.1 → meshcode-1.7.0}/meshcode.egg-info/top_level.txt +0 -0
  30. {meshcode-1.5.1 → meshcode-1.7.0}/setup.cfg +0 -0
@@ -0,0 +1,220 @@
1
+ Metadata-Version: 2.4
2
+ Name: meshcode
3
+ Version: 1.7.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
@@ -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.5.1"
2
+ __version__ = "1.7.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
- ack_targets = {m["from_agent"] for m in messages if m.get("type") not in ("ack", "broadcast")}
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,
@@ -235,6 +257,47 @@ def set_status(project_id: str, agent: str, status: str, task: str = "") -> Dict
235
257
  return {"ok": True, "status": status}
236
258
 
237
259
 
260
+ def task_create(api_key, project_id, creator_agent, title, description="", assignee="*", priority="normal", parent_task_id=None):
261
+ return sb_rpc("mc_task_create", {
262
+ "p_api_key": api_key,
263
+ "p_project_id": project_id,
264
+ "p_creator_agent": creator_agent,
265
+ "p_title": title,
266
+ "p_description": description,
267
+ "p_assignee": assignee,
268
+ "p_priority": priority,
269
+ "p_parent_task_id": parent_task_id,
270
+ })
271
+
272
+
273
+ def task_list(api_key, project_id, agent, status_filter=None):
274
+ return sb_rpc("mc_task_list", {
275
+ "p_api_key": api_key,
276
+ "p_project_id": project_id,
277
+ "p_agent": agent,
278
+ "p_status_filter": status_filter,
279
+ })
280
+
281
+
282
+ def task_claim(api_key, project_id, task_id, claiming_agent):
283
+ return sb_rpc("mc_task_claim", {
284
+ "p_api_key": api_key,
285
+ "p_project_id": project_id,
286
+ "p_task_id": task_id,
287
+ "p_claiming_agent": claiming_agent,
288
+ })
289
+
290
+
291
+ def task_complete(api_key, project_id, task_id, completing_agent, summary=""):
292
+ return sb_rpc("mc_task_complete", {
293
+ "p_api_key": api_key,
294
+ "p_project_id": project_id,
295
+ "p_task_id": task_id,
296
+ "p_completing_agent": completing_agent,
297
+ "p_summary": summary,
298
+ })
299
+
300
+
238
301
  def get_history(project_id: str, limit: int = 20) -> List[Dict]:
239
302
  return sb_select(
240
303
  "mc_messages",
@@ -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.