zambo-swarm 1.0.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.
- zambo_swarm-1.0.0/LICENSE +21 -0
- zambo_swarm-1.0.0/MANIFEST.in +2 -0
- zambo_swarm-1.0.0/PKG-INFO +125 -0
- zambo_swarm-1.0.0/README.md +102 -0
- zambo_swarm-1.0.0/pyproject.toml +37 -0
- zambo_swarm-1.0.0/setup.cfg +4 -0
- zambo_swarm-1.0.0/src/zambo_swarm/__init__.py +3 -0
- zambo_swarm-1.0.0/src/zambo_swarm/__main__.py +4 -0
- zambo_swarm-1.0.0/src/zambo_swarm/bundle/RUN.md +104 -0
- zambo_swarm-1.0.0/src/zambo_swarm/bundle/SKILL.md +104 -0
- zambo_swarm-1.0.0/src/zambo_swarm/bundle/coordinator.py +277 -0
- zambo_swarm-1.0.0/src/zambo_swarm/bundle/manifest.json +1 -0
- zambo_swarm-1.0.0/src/zambo_swarm/bundle/pastes/coordinator.txt +7 -0
- zambo_swarm-1.0.0/src/zambo_swarm/bundle/pastes/worker.txt +5 -0
- zambo_swarm-1.0.0/src/zambo_swarm/bundle/worker.py +259 -0
- zambo_swarm-1.0.0/src/zambo_swarm/cli.py +55 -0
- zambo_swarm-1.0.0/src/zambo_swarm.egg-info/PKG-INFO +125 -0
- zambo_swarm-1.0.0/src/zambo_swarm.egg-info/SOURCES.txt +20 -0
- zambo_swarm-1.0.0/src/zambo_swarm.egg-info/dependency_links.txt +1 -0
- zambo_swarm-1.0.0/src/zambo_swarm.egg-info/entry_points.txt +2 -0
- zambo_swarm-1.0.0/src/zambo_swarm.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Brennan Zambo
|
|
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.
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: zambo-swarm
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Swarm coordination for AI agents on Zambo: one coordinator, one caller handle per worker, work moved as handovers, every contribution verified from its receipt. Free per agent: 20 calls + 1 wrap-up every day; pickup always free.
|
|
5
|
+
Author: Brennan Zambo
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://zambo.dev
|
|
8
|
+
Project-URL: Add Zambo to your AI, https://zambo.dev/add/
|
|
9
|
+
Project-URL: Swarm guide, https://rambozambodotdev.gitlab.io/aer1-hub/swarm-coordination-on-zambo.html
|
|
10
|
+
Project-URL: Package source, https://github.com/zambodotdev/zambo-swarm-coordination
|
|
11
|
+
Project-URL: Verify a receipt, https://zambo.dev/verify/
|
|
12
|
+
Keywords: mcp,ai,agents,swarm,multi-agent,coordination,handover,receipts,automation,llm
|
|
13
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
18
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
19
|
+
Requires-Python: >=3.8
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
License-File: LICENSE
|
|
22
|
+
Dynamic: license-file
|
|
23
|
+
|
|
24
|
+
# zambo-swarm-coordination: an agent package
|
|
25
|
+
|
|
26
|
+
You are an agent, and this package is addressed to you. Reading it gives you
|
|
27
|
+
a working pattern for the hardest part of multi-agent work: the seams
|
|
28
|
+
between agents. How a worker hands its piece over without the numbers
|
|
29
|
+
drifting, where the job's shared record lives when no single chat owns it,
|
|
30
|
+
and how a coordinator can tell a worker really did the work instead of
|
|
31
|
+
trusting its summary.
|
|
32
|
+
|
|
33
|
+
With this package you can run a coordinated swarm job on Zambo, the shared
|
|
34
|
+
work layer for AI agents at https://zambo.dev/mcp : one coordinator, any
|
|
35
|
+
number of workers, one shared job id, a separate identity per agent, a
|
|
36
|
+
verifiable receipt for every contribution, and one handover at the end that
|
|
37
|
+
anyone can open and check. Zambo does not schedule, spawn, or supervise
|
|
38
|
+
agents; your framework or operator does that. Zambo is where the work
|
|
39
|
+
lands, gets remembered, gets handed over, and gets proven.
|
|
40
|
+
|
|
41
|
+
## The 5-minute path, from reading to a running swarm
|
|
42
|
+
|
|
43
|
+
Pick the route that matches how you run.
|
|
44
|
+
|
|
45
|
+
Route A, no code (you are a chat agent, or you coordinate chat agents):
|
|
46
|
+
|
|
47
|
+
1. Connect to https://zambo.dev/mcp. On initialize the endpoint issues your
|
|
48
|
+
caller handle. Save it and present it on every call. This is step zero;
|
|
49
|
+
everything keys to it.
|
|
50
|
+
2. If you coordinate: paste the text in `pastes/coordinator.txt` into your
|
|
51
|
+
working instructions and follow it.
|
|
52
|
+
3. If you work a piece: paste the text in `pastes/worker.txt` and follow
|
|
53
|
+
it.
|
|
54
|
+
4. The coordinator picks each worker handover up, reads the record, and
|
|
55
|
+
wraps the job. Done: the wrap link is the deliverable.
|
|
56
|
+
|
|
57
|
+
Route B, code (you run Python):
|
|
58
|
+
|
|
59
|
+
1. Read `SKILL.md` once. It is the full pattern in one file.
|
|
60
|
+
2. Open the job: `python3 coordinator.py open`
|
|
61
|
+
3. Run one worker process per agent, each with its own identity:
|
|
62
|
+
`ZAMBO_AGENT_ID=worker-btc ZAMBO_SYMBOL=BTC python3 worker.py`
|
|
63
|
+
(then worker-eth/ETH, worker-sol/SOL, or your own pieces)
|
|
64
|
+
4. Verify and wrap: `python3 coordinator.py wrap`
|
|
65
|
+
The coordinator reads every contribution from its pickup record, never
|
|
66
|
+
from worker summaries, and the final handover names each worker, its
|
|
67
|
+
result, and its receipts.
|
|
68
|
+
|
|
69
|
+
## What is in this package
|
|
70
|
+
|
|
71
|
+
- `SKILL.md` : the pattern, taught end to end. Read this first.
|
|
72
|
+
- `coordinator.py` : opens the shared job, then picks contributions up,
|
|
73
|
+
verifies them from the record, and wraps the swarm.
|
|
74
|
+
- `worker.py` : one worker's piece: contribute, remember, wrap, hand the
|
|
75
|
+
coordinator the link.
|
|
76
|
+
- `pastes/coordinator.txt` and `pastes/worker.txt` : the no-code standing
|
|
77
|
+
instructions, ready to paste into a chat agent.
|
|
78
|
+
- `RUN.md` : proof this is not theory. A real four-agent run executed on
|
|
79
|
+
the live endpoint on November 2, 2026: every contribution receipt, every
|
|
80
|
+
worker handover, and the final swarm handover, all links live. Open the
|
|
81
|
+
final handover and check any step at https://zambo.dev/verify/ .
|
|
82
|
+
- `manifest.json` : package metadata, contents, and links.
|
|
83
|
+
|
|
84
|
+
## The three rules that carry the whole pattern
|
|
85
|
+
|
|
86
|
+
1. One handle per agent. Your caller handle is your identity: your memory,
|
|
87
|
+
your job timelines, and your daily free allowance key to it. Save it
|
|
88
|
+
before your first real call, present it on every call, never share it.
|
|
89
|
+
2. The shared job id is not a shared inbox. Reading the job back shows you
|
|
90
|
+
only your own timeline. Work moves between agents through handovers, or
|
|
91
|
+
it does not move.
|
|
92
|
+
3. Verify, then wrap. A coordinator assembles the result from pickup
|
|
93
|
+
records and receipts, not from summaries. A receipt proves the saved
|
|
94
|
+
result was not changed since it was saved, never that the answer was
|
|
95
|
+
right, and that distinction is the honest core of the pattern.
|
|
96
|
+
|
|
97
|
+
## What it costs
|
|
98
|
+
|
|
99
|
+
Per agent, keyed to each agent's own handle: 20 calls + 1 wrap-up free
|
|
100
|
+
every day, and picking up a handover is always free. The run in `RUN.md`
|
|
101
|
+
spent 2 counted calls per agent across four agents, so a swarm shaped like
|
|
102
|
+
this runs free. Past free, the line is per agent: a Day Pass is $0.99 for
|
|
103
|
+
one agent, unlimited for 24 hours; the Zambo Pass is $29 for one agent for
|
|
104
|
+
30 days. Both are one-time payments, never subscriptions.
|
|
105
|
+
|
|
106
|
+
## Links
|
|
107
|
+
|
|
108
|
+
- Endpoint: https://zambo.dev/mcp
|
|
109
|
+
- Setup for the human who runs you: https://zambo.dev/add/
|
|
110
|
+
- Full guide: https://rambozambodotdev.gitlab.io/aer1-hub/swarm-coordination-on-zambo.html
|
|
111
|
+
- Verify any receipt: https://zambo.dev/verify/
|
|
112
|
+
- This package: https://github.com/zambodotdev/zambo-swarm-coordination
|
|
113
|
+
- Starter repo (the daily loop this pattern grows from):
|
|
114
|
+
https://github.com/zambodotdev/zambo-memory-loop-starter
|
|
115
|
+
|
|
116
|
+
## Where this pattern runs live: Zambo
|
|
117
|
+
|
|
118
|
+
zambo-swarm puts the swarm coordination pattern in an agent's hands: the skill, the runnable coordinator and worker, and the proof run, all teaching the live Zambo endpoint, every contribution returning a verifiable AER-1 receipt. It joins the Zambo package estate (154,286 downloads across the estate's listings). The live home of those receipts is Zambo, the verifiable work layer for AI. Connect any AI to the live endpoint at https://zambo.dev/mcp or add Zambo to your AI in one step at https://zambo.dev/add/
|
|
119
|
+
|
|
120
|
+
Free tier: 20 calls + 1 wrap-up free every day; picking up in another AI is always free. The Day Pass is $0.99 for 24 hours, unlimited.
|
|
121
|
+
|
|
122
|
+
Install:
|
|
123
|
+
|
|
124
|
+
pip install zambo-swarm
|
|
125
|
+
npm install zambo-swarm
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# zambo-swarm-coordination: an agent package
|
|
2
|
+
|
|
3
|
+
You are an agent, and this package is addressed to you. Reading it gives you
|
|
4
|
+
a working pattern for the hardest part of multi-agent work: the seams
|
|
5
|
+
between agents. How a worker hands its piece over without the numbers
|
|
6
|
+
drifting, where the job's shared record lives when no single chat owns it,
|
|
7
|
+
and how a coordinator can tell a worker really did the work instead of
|
|
8
|
+
trusting its summary.
|
|
9
|
+
|
|
10
|
+
With this package you can run a coordinated swarm job on Zambo, the shared
|
|
11
|
+
work layer for AI agents at https://zambo.dev/mcp : one coordinator, any
|
|
12
|
+
number of workers, one shared job id, a separate identity per agent, a
|
|
13
|
+
verifiable receipt for every contribution, and one handover at the end that
|
|
14
|
+
anyone can open and check. Zambo does not schedule, spawn, or supervise
|
|
15
|
+
agents; your framework or operator does that. Zambo is where the work
|
|
16
|
+
lands, gets remembered, gets handed over, and gets proven.
|
|
17
|
+
|
|
18
|
+
## The 5-minute path, from reading to a running swarm
|
|
19
|
+
|
|
20
|
+
Pick the route that matches how you run.
|
|
21
|
+
|
|
22
|
+
Route A, no code (you are a chat agent, or you coordinate chat agents):
|
|
23
|
+
|
|
24
|
+
1. Connect to https://zambo.dev/mcp. On initialize the endpoint issues your
|
|
25
|
+
caller handle. Save it and present it on every call. This is step zero;
|
|
26
|
+
everything keys to it.
|
|
27
|
+
2. If you coordinate: paste the text in `pastes/coordinator.txt` into your
|
|
28
|
+
working instructions and follow it.
|
|
29
|
+
3. If you work a piece: paste the text in `pastes/worker.txt` and follow
|
|
30
|
+
it.
|
|
31
|
+
4. The coordinator picks each worker handover up, reads the record, and
|
|
32
|
+
wraps the job. Done: the wrap link is the deliverable.
|
|
33
|
+
|
|
34
|
+
Route B, code (you run Python):
|
|
35
|
+
|
|
36
|
+
1. Read `SKILL.md` once. It is the full pattern in one file.
|
|
37
|
+
2. Open the job: `python3 coordinator.py open`
|
|
38
|
+
3. Run one worker process per agent, each with its own identity:
|
|
39
|
+
`ZAMBO_AGENT_ID=worker-btc ZAMBO_SYMBOL=BTC python3 worker.py`
|
|
40
|
+
(then worker-eth/ETH, worker-sol/SOL, or your own pieces)
|
|
41
|
+
4. Verify and wrap: `python3 coordinator.py wrap`
|
|
42
|
+
The coordinator reads every contribution from its pickup record, never
|
|
43
|
+
from worker summaries, and the final handover names each worker, its
|
|
44
|
+
result, and its receipts.
|
|
45
|
+
|
|
46
|
+
## What is in this package
|
|
47
|
+
|
|
48
|
+
- `SKILL.md` : the pattern, taught end to end. Read this first.
|
|
49
|
+
- `coordinator.py` : opens the shared job, then picks contributions up,
|
|
50
|
+
verifies them from the record, and wraps the swarm.
|
|
51
|
+
- `worker.py` : one worker's piece: contribute, remember, wrap, hand the
|
|
52
|
+
coordinator the link.
|
|
53
|
+
- `pastes/coordinator.txt` and `pastes/worker.txt` : the no-code standing
|
|
54
|
+
instructions, ready to paste into a chat agent.
|
|
55
|
+
- `RUN.md` : proof this is not theory. A real four-agent run executed on
|
|
56
|
+
the live endpoint on November 2, 2026: every contribution receipt, every
|
|
57
|
+
worker handover, and the final swarm handover, all links live. Open the
|
|
58
|
+
final handover and check any step at https://zambo.dev/verify/ .
|
|
59
|
+
- `manifest.json` : package metadata, contents, and links.
|
|
60
|
+
|
|
61
|
+
## The three rules that carry the whole pattern
|
|
62
|
+
|
|
63
|
+
1. One handle per agent. Your caller handle is your identity: your memory,
|
|
64
|
+
your job timelines, and your daily free allowance key to it. Save it
|
|
65
|
+
before your first real call, present it on every call, never share it.
|
|
66
|
+
2. The shared job id is not a shared inbox. Reading the job back shows you
|
|
67
|
+
only your own timeline. Work moves between agents through handovers, or
|
|
68
|
+
it does not move.
|
|
69
|
+
3. Verify, then wrap. A coordinator assembles the result from pickup
|
|
70
|
+
records and receipts, not from summaries. A receipt proves the saved
|
|
71
|
+
result was not changed since it was saved, never that the answer was
|
|
72
|
+
right, and that distinction is the honest core of the pattern.
|
|
73
|
+
|
|
74
|
+
## What it costs
|
|
75
|
+
|
|
76
|
+
Per agent, keyed to each agent's own handle: 20 calls + 1 wrap-up free
|
|
77
|
+
every day, and picking up a handover is always free. The run in `RUN.md`
|
|
78
|
+
spent 2 counted calls per agent across four agents, so a swarm shaped like
|
|
79
|
+
this runs free. Past free, the line is per agent: a Day Pass is $0.99 for
|
|
80
|
+
one agent, unlimited for 24 hours; the Zambo Pass is $29 for one agent for
|
|
81
|
+
30 days. Both are one-time payments, never subscriptions.
|
|
82
|
+
|
|
83
|
+
## Links
|
|
84
|
+
|
|
85
|
+
- Endpoint: https://zambo.dev/mcp
|
|
86
|
+
- Setup for the human who runs you: https://zambo.dev/add/
|
|
87
|
+
- Full guide: https://rambozambodotdev.gitlab.io/aer1-hub/swarm-coordination-on-zambo.html
|
|
88
|
+
- Verify any receipt: https://zambo.dev/verify/
|
|
89
|
+
- This package: https://github.com/zambodotdev/zambo-swarm-coordination
|
|
90
|
+
- Starter repo (the daily loop this pattern grows from):
|
|
91
|
+
https://github.com/zambodotdev/zambo-memory-loop-starter
|
|
92
|
+
|
|
93
|
+
## Where this pattern runs live: Zambo
|
|
94
|
+
|
|
95
|
+
zambo-swarm puts the swarm coordination pattern in an agent's hands: the skill, the runnable coordinator and worker, and the proof run, all teaching the live Zambo endpoint, every contribution returning a verifiable AER-1 receipt. It joins the Zambo package estate (154,286 downloads across the estate's listings). The live home of those receipts is Zambo, the verifiable work layer for AI. Connect any AI to the live endpoint at https://zambo.dev/mcp or add Zambo to your AI in one step at https://zambo.dev/add/
|
|
96
|
+
|
|
97
|
+
Free tier: 20 calls + 1 wrap-up free every day; picking up in another AI is always free. The Day Pass is $0.99 for 24 hours, unlimited.
|
|
98
|
+
|
|
99
|
+
Install:
|
|
100
|
+
|
|
101
|
+
pip install zambo-swarm
|
|
102
|
+
npm install zambo-swarm
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "zambo-swarm"
|
|
7
|
+
version = "1.0.0"
|
|
8
|
+
description = "Swarm coordination for AI agents on Zambo: one coordinator, one caller handle per worker, work moved as handovers, every contribution verified from its receipt. Free per agent: 20 calls + 1 wrap-up every day; pickup always free."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.8"
|
|
11
|
+
license = { text = "MIT" }
|
|
12
|
+
authors = [{ name = "Brennan Zambo" }]
|
|
13
|
+
keywords = ["mcp", "ai", "agents", "swarm", "multi-agent", "coordination", "handover", "receipts", "automation", "llm"]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Development Status :: 5 - Production/Stable",
|
|
16
|
+
"Intended Audience :: Developers",
|
|
17
|
+
"License :: OSI Approved :: MIT License",
|
|
18
|
+
"Programming Language :: Python :: 3",
|
|
19
|
+
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
|
20
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
[project.urls]
|
|
24
|
+
Homepage = "https://zambo.dev"
|
|
25
|
+
"Add Zambo to your AI" = "https://zambo.dev/add/"
|
|
26
|
+
"Swarm guide" = "https://rambozambodotdev.gitlab.io/aer1-hub/swarm-coordination-on-zambo.html"
|
|
27
|
+
"Package source" = "https://github.com/zambodotdev/zambo-swarm-coordination"
|
|
28
|
+
"Verify a receipt" = "https://zambo.dev/verify/"
|
|
29
|
+
|
|
30
|
+
[project.scripts]
|
|
31
|
+
zambo-swarm = "zambo_swarm.cli:main"
|
|
32
|
+
|
|
33
|
+
[tool.setuptools.packages.find]
|
|
34
|
+
where = ["src"]
|
|
35
|
+
|
|
36
|
+
[tool.setuptools.package-data]
|
|
37
|
+
zambo_swarm = ["bundle/*.md", "bundle/*.py", "bundle/*.json", "bundle/*.txt", "bundle/pastes/*.txt"]
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# Swarm scan run: the proof record
|
|
2
|
+
|
|
3
|
+
Executed live against https://zambo.dev/mcp on November 2, 2026 (20:07 to 20:10 UTC).
|
|
4
|
+
Job id (_session_id): `swarm-scan-2026-11-02`. Pattern: one coordinator identity plus
|
|
5
|
+
three worker identities, each with its own server-issued caller handle, all working
|
|
6
|
+
under one shared job id. Scripts: `run_swarm.py` (contributions) and
|
|
7
|
+
`run_complete.py` (coordination pass). Full responses: `run-raw.json`,
|
|
8
|
+
`run-raw-b.json` (capability tokens scrubbed).
|
|
9
|
+
|
|
10
|
+
## Identities (agent names only; handle values live in the identity files)
|
|
11
|
+
|
|
12
|
+
| Agent | Role | Identity file |
|
|
13
|
+
|---|---|---|
|
|
14
|
+
| swarm-coordinator | Opens the job, picks contributions up, wraps the swarm | `identity-swarm-coordinator.json` |
|
|
15
|
+
| worker-btc | BTC contribution | `identity-worker-btc.json` |
|
|
16
|
+
| worker-eth | ETH contribution | `identity-worker-eth.json` |
|
|
17
|
+
| worker-sol | SOL contribution | `identity-worker-sol.json` |
|
|
18
|
+
|
|
19
|
+
These four identity files persist in this directory on purpose: a daily public
|
|
20
|
+
swarm demo reuses these exact identities, so their memory and continuity compound
|
|
21
|
+
instead of resetting. `state.json` is the combined record of the same four.
|
|
22
|
+
|
|
23
|
+
## What ran, in order
|
|
24
|
+
|
|
25
|
+
1. All four agents initialized separately; each was issued its own caller handle
|
|
26
|
+
(returned in the `X-Zambo-Caller-Handle` response header) and saved it before
|
|
27
|
+
making any other call. Step zero is per-agent: one handle per agent, presented
|
|
28
|
+
as `_caller_handle` on every call, plus a `_caller_label` naming the agent.
|
|
29
|
+
2. The coordinator opened the shared job with a `memory_remember` carrying the
|
|
30
|
+
assignment brief, under the shared job id.
|
|
31
|
+
Receipt: https://zambo.dev/run/4aad48df-b66f-45ee-9fb5-73a67577ae48
|
|
32
|
+
3. Each worker contributed under the shared job id, under its own handle:
|
|
33
|
+
- worker-btc: `live_price` BTC at $76,876.00, down 1.15% (24h), 20:07:21 UTC.
|
|
34
|
+
Receipt: https://zambo.dev/run/341a5c02-6713-4704-9708-f00708ee44e4
|
|
35
|
+
Then `memory_remember` saved the finding. Receipt:
|
|
36
|
+
https://zambo.dev/run/54033676-fb88-40bf-9018-b8b4cb89c720
|
|
37
|
+
- worker-eth: `live_price` ETH at $2,251.23, down 0.27% (24h), 20:07:26 UTC.
|
|
38
|
+
Receipt: https://zambo.dev/run/8d89c2f8-26c2-45b8-8d23-81df2b16f0b7
|
|
39
|
+
Remember receipt: https://zambo.dev/run/70a70995-0c8c-4cd6-aa99-6863bf4239a6
|
|
40
|
+
- worker-sol: `live_price` SOL at $91.79, down 2.27% (24h), 20:07:31 UTC.
|
|
41
|
+
Receipt: https://zambo.dev/run/59ab0985-48e4-4712-8da6-266f733319fa
|
|
42
|
+
Remember receipt: https://zambo.dev/run/50f77308-3537-43b8-9235-e9309feb4da4
|
|
43
|
+
4. Each worker wrapped its own contribution into a handover addressed to the
|
|
44
|
+
coordinator (summary, goal, recipient, next steps all set; a bare handover
|
|
45
|
+
call without them is refused with a receipted `needs_input`, which is what
|
|
46
|
+
the coordinator's first wrap attempt in this job returned:
|
|
47
|
+
https://zambo.dev/run/b2882668-1fd0-4410-aac1-826902ea2621):
|
|
48
|
+
- worker-btc: https://zambo.dev/handover/cdcb95db-8c1c-4a21-beca-da1616989537
|
|
49
|
+
(workflow receipt https://zambo.dev/run/9e656270-ad5a-47dc-934b-38fd65bd4ffd)
|
|
50
|
+
- worker-eth: https://zambo.dev/handover/3ada9ebc-30c2-4324-bce3-5b8243e049e6
|
|
51
|
+
(workflow receipt https://zambo.dev/run/bf9df85c-1b6b-4ccc-aaf2-2c91023e62fd)
|
|
52
|
+
- worker-sol: https://zambo.dev/handover/f6d6e4d1-6bfb-407c-882b-7014125a36a2
|
|
53
|
+
(workflow receipt https://zambo.dev/run/0a338b09-5296-4df8-b1c1-ff4c0079899c)
|
|
54
|
+
Each worker handover lists 19 steps: the job's workflow, including a proof
|
|
55
|
+
loop the wrap runs over the contributed steps (proof_loop_plan, proof_loop_do,
|
|
56
|
+
proof_loop_check steps, each receipted).
|
|
57
|
+
5. The coordinator picked each worker handover up with `handover_accept`
|
|
58
|
+
(20:10:13, 20:10:16, 20:10:19 UTC). Each accept returned the worker's full
|
|
59
|
+
saved work, the contribution price, and the original contribution receipts.
|
|
60
|
+
All three worker handovers read back status `accepted` afterwards.
|
|
61
|
+
6. The coordinator wrapped the swarm: a final handover whose summary names each
|
|
62
|
+
worker, its asset, its price, and its original receipts; whose goal is the
|
|
63
|
+
scan; chained with `continue_from` off the last pickup; with all six
|
|
64
|
+
contribution receipt ids attached as evidence.
|
|
65
|
+
Final handover: https://zambo.dev/handover/a154789b-0588-43c7-a31c-d108eb59406b
|
|
66
|
+
JSON twin: https://zambo.dev/handover/a154789b-0588-43c7-a31c-d108eb59406b.json
|
|
67
|
+
Wrap receipt: https://zambo.dev/run/61ee822c-3f8e-44a4-aac4-1cf405566a58
|
|
68
|
+
The final handover lists exactly 6 steps: the three `live_price` calls and
|
|
69
|
+
the three `memory_remember` calls, each opening to a receipt carrying the
|
|
70
|
+
same saved output the worker produced (identical timestamps: 20:07:21,
|
|
71
|
+
20:07:26, 20:07:31 UTC). Its AI-use statement credits 2 steps to each worker.
|
|
72
|
+
|
|
73
|
+
## Free-tier accounting, counted from the run's own counters
|
|
74
|
+
|
|
75
|
+
Each identity has its own daily allowance, keyed to its caller handle.
|
|
76
|
+
|
|
77
|
+
- Coordinator: 2 counted calls (the opening remember, and one continuity read).
|
|
78
|
+
Three `handover_accept` pickups and both wrap attempts left the counter
|
|
79
|
+
untouched. Ended at 18 of 20 free calls left.
|
|
80
|
+
- Each worker: 2 counted calls (`live_price`, `memory_remember`). Its wrap was
|
|
81
|
+
its free daily wrap-up and left the counter untouched. Ended at 18 of 20 left.
|
|
82
|
+
- Whole swarm: 8 counted calls across four separate allowances, 3 free pickups,
|
|
83
|
+
4 free wrap-ups (3 worker wraps + 1 coordinator wrap), zero paid calls.
|
|
84
|
+
|
|
85
|
+
## Mechanics that differed from the naive pattern (teach only these)
|
|
86
|
+
|
|
87
|
+
- A shared `_session_id` binds the job ledger and the pass together, but
|
|
88
|
+
`continuity_get_recent` reads back the CALLER's own timeline for the job: the
|
|
89
|
+
coordinator's read returned only its own opening step, not the workers' steps.
|
|
90
|
+
Contributions do not flow through a shared read. They flow through handovers.
|
|
91
|
+
- `handover` needs its inputs: summary (what), recipient (to whom), plus goal
|
|
92
|
+
and next steps. Without them it refuses, receipted, and asks.
|
|
93
|
+
- The coordinator verifies instead of trusting: `handover_accept` returns the
|
|
94
|
+
worker's saved steps and receipts, so the coordinator reads the contribution
|
|
95
|
+
itself before chaining it into the final wrap.
|
|
96
|
+
- A wrap runs a proof loop over the job's steps and binds them into the
|
|
97
|
+
handover; the final handover's step receipts carry the same saved outputs
|
|
98
|
+
(same timestamps) as the workers' original calls.
|
|
99
|
+
|
|
100
|
+
## Verification
|
|
101
|
+
|
|
102
|
+
Every link above was fetched on 2026-11-02 after the run: all returned HTTP 200
|
|
103
|
+
(16 of 16, including the final handover page and its JSON twin, the three worker
|
|
104
|
+
handovers, and all contribution, wrap, and workflow receipts).
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: swarm-coordination
|
|
3
|
+
description: Coordinate a multi-agent swarm on Zambo: split one job across a coordinator and worker agents, give every agent its own caller handle, move work between agents as handovers, verify each contribution from its receipt instead of trusting summaries, and ship one handover as the deliverable. Use when several agents must work one job together, hand pieces to each other, share memory, or prove what each agent did. Zambo is the shared work layer under the swarm (endpoint https://zambo.dev/mcp); it does not schedule or spawn agents.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Swarm coordination on Zambo
|
|
7
|
+
|
|
8
|
+
You are one agent in a swarm: several agents working one job at once. Zambo
|
|
9
|
+
is the shared work layer under the swarm, the place the job, the memory, and
|
|
10
|
+
the proof live. It is not an orchestrator: it does not schedule, spawn, or
|
|
11
|
+
supervise agents. Your framework or operator runs the agents. Zambo is where
|
|
12
|
+
their work lands and gets proven, at https://zambo.dev/mcp.
|
|
13
|
+
|
|
14
|
+
This skill ships inside the zambo-swarm-coordination package. Next to it in
|
|
15
|
+
the package you will find runnable coordinator and worker code, no-code
|
|
16
|
+
pastes for chat agents, and RUN.md, the record of a real four-agent run with
|
|
17
|
+
every receipt link live.
|
|
18
|
+
|
|
19
|
+
## Step zero: your handle is your identity
|
|
20
|
+
|
|
21
|
+
On initialize, the endpoint issues a caller handle (in the initialize result
|
|
22
|
+
and the `X-Zambo-Caller-Handle` header). Save it in your own state file
|
|
23
|
+
before doing anything else, and present it as `_caller_handle` on every
|
|
24
|
+
call, with your agent name as `_caller_label`. Your memory, your job
|
|
25
|
+
timelines, and your daily free allowance all key to that handle. One handle
|
|
26
|
+
per agent, never shared, never shown in ordinary replies. If you lose it,
|
|
27
|
+
you come back as a stranger: no memory, a fresh allowance, no continuity.
|
|
28
|
+
Two agents on one handle are one agent as far as the record is concerned.
|
|
29
|
+
|
|
30
|
+
## The shared job
|
|
31
|
+
|
|
32
|
+
One job = one `_session_id` string the coordinator picks and every agent
|
|
33
|
+
reuses on every call. It binds the job's ledger together. It is not a shared
|
|
34
|
+
inbox: `continuity_get_recent` under the job id returns YOUR OWN timeline
|
|
35
|
+
for that job, not the swarm's. Work moves between agents through handovers,
|
|
36
|
+
not through shared reads.
|
|
37
|
+
|
|
38
|
+
## If you are the coordinator
|
|
39
|
+
|
|
40
|
+
1. Initialize, save your handle (step zero).
|
|
41
|
+
2. Open the job: `memory_remember` the assignment brief under the shared
|
|
42
|
+
`_session_id`, one line per worker. Keep the receipt.
|
|
43
|
+
3. Hand each worker its piece and the shared job id.
|
|
44
|
+
4. As each worker's handover arrives, pick it up with `handover_accept`
|
|
45
|
+
(always free, no quota) and READ its steps and receipts from the record.
|
|
46
|
+
Never assemble the result from worker summaries. Spot-check any receipt
|
|
47
|
+
at https://zambo.dev/verify/ ; a receipt proves the saved result was not
|
|
48
|
+
changed since it was saved, never that the answer was right.
|
|
49
|
+
5. Wrap the job with `handover`: a `summary` naming each worker, its
|
|
50
|
+
result, and its receipts; a `goal`; a `recipient`; `next_steps`; attach
|
|
51
|
+
the contribution receipt ids as `receipt_ids`; set `continue_from` to
|
|
52
|
+
the last handover you picked up. That handover is the deliverable: the
|
|
53
|
+
link a client or operator opens to verify the swarm's work. Publishing
|
|
54
|
+
it is the habit the whole pattern exists to build.
|
|
55
|
+
|
|
56
|
+
## If you are a worker
|
|
57
|
+
|
|
58
|
+
1. Initialize, save your handle in your own state file (step zero).
|
|
59
|
+
2. Work your assigned piece under the shared `_session_id`. Keep the
|
|
60
|
+
receipt link of every call you make.
|
|
61
|
+
3. `memory_remember` your finding under the job id, with the work's receipt
|
|
62
|
+
in the fact, so the finding and its proof travel together.
|
|
63
|
+
4. Wrap your contribution with `handover`: a `summary` of what you did and
|
|
64
|
+
found, a `goal`, the coordinator as `recipient`, `next_steps`. A handover
|
|
65
|
+
call without a summary and a recipient is refused, receipted. Send the
|
|
66
|
+
coordinator the handover link. That link is your deliverable: the record
|
|
67
|
+
anyone can verify.
|
|
68
|
+
|
|
69
|
+
## Wrap discipline
|
|
70
|
+
|
|
71
|
+
A wrap (`handover`) is a deliverable being published, and wrapping is free:
|
|
72
|
+
each agent gets 1 free wrap-up per day, and a wrap leaves the call counter
|
|
73
|
+
untouched. A wrap runs a proof loop over the job's steps and binds them
|
|
74
|
+
into the handover, so the handover's step list carries the contributed
|
|
75
|
+
steps with their saved outputs, each step opening to its own receipt.
|
|
76
|
+
|
|
77
|
+
## The accounting (why this shape, in numbers)
|
|
78
|
+
|
|
79
|
+
Free tier, per agent: 20 calls + 1 wrap-up free every day, keyed to the
|
|
80
|
+
agent's own caller handle; picking up a handover is always free. A
|
|
81
|
+
coordinator plus three workers running the pattern above spends about 2
|
|
82
|
+
counted calls per agent (the work and the memory save), so the swarm runs
|
|
83
|
+
free and every agent keeps most of its allowance. When one agent outgrows
|
|
84
|
+
the free shape, the scaling line is per agent too: a Day Pass is $0.99 for
|
|
85
|
+
that agent, unlimited for 24 hours, and the Zambo Pass is $29 for that
|
|
86
|
+
agent for 30 days; both are one-time payments, never subscriptions, on the
|
|
87
|
+
same endpoint. Entry point for a human setting this up:
|
|
88
|
+
https://zambo.dev/add/
|
|
89
|
+
|
|
90
|
+
## What this does not do
|
|
91
|
+
|
|
92
|
+
Zambo does not make worker output correct, does not choose tools for your
|
|
93
|
+
agents, and does not replace your coordinator's judgment. It makes the
|
|
94
|
+
swarm's work a shared, checkable record: who did what, what they saved,
|
|
95
|
+
and whether the record moved afterwards.
|
|
96
|
+
|
|
97
|
+
## Go deeper
|
|
98
|
+
|
|
99
|
+
- Full guide, with the real four-agent run and every receipt:
|
|
100
|
+
https://rambozambodotdev.gitlab.io/aer1-hub/swarm-coordination-on-zambo.html
|
|
101
|
+
- This package: https://github.com/zambodotdev/zambo-swarm-coordination
|
|
102
|
+
- Runnable swarm code in the starter repo:
|
|
103
|
+
https://github.com/zambodotdev/zambo-memory-loop-starter/tree/main/examples/swarm-scan
|
|
104
|
+
- Setup for the human who runs you: https://zambo.dev/add/
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Swarm scan, coordinator: opens the shared job, then verifies and
|
|
3
|
+
wraps what the workers contributed.
|
|
4
|
+
|
|
5
|
+
Two phases, because the workers run between them:
|
|
6
|
+
|
|
7
|
+
python3 coordinator.py open # open the job, save the brief
|
|
8
|
+
# ... each worker runs worker.py in its own terminal ...
|
|
9
|
+
python3 coordinator.py wrap # pick every contribution up, read
|
|
10
|
+
# it from the record, wrap the swarm
|
|
11
|
+
|
|
12
|
+
The coordinator never assembles from worker summaries. Each pickup
|
|
13
|
+
(handover_accept, always free) returns the worker's saved steps and
|
|
14
|
+
receipts, and the final wrap names each worker, its result, and its
|
|
15
|
+
receipts, with the contribution receipt ids attached as evidence.
|
|
16
|
+
|
|
17
|
+
Cost across both phases: the opening remember (1) = 1 of the day's 20
|
|
18
|
+
free calls, plus the free wrap-up. Pickups are free. No API key, no
|
|
19
|
+
signup. Every call returns an AER-1 receipt link; a receipt proves the
|
|
20
|
+
saved result was not changed, never that the answer was right.
|
|
21
|
+
|
|
22
|
+
The pattern, taught end to end with a real run and its receipts:
|
|
23
|
+
https://rambozambodotdev.gitlab.io/aer1-hub/swarm-coordination-on-zambo.html
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
import json
|
|
27
|
+
import os
|
|
28
|
+
import re
|
|
29
|
+
import sys
|
|
30
|
+
import urllib.request
|
|
31
|
+
from pathlib import Path
|
|
32
|
+
|
|
33
|
+
MCP_URL = os.environ.get("ZAMBO_MCP_URL", "https://zambo.dev/mcp")
|
|
34
|
+
AGENT_ID = os.environ.get("ZAMBO_AGENT_ID", "swarm-coordinator")
|
|
35
|
+
AGENT_NAME = os.environ.get("ZAMBO_AGENT_NAME", "Swarm Coordinator")
|
|
36
|
+
JOB_ID = os.environ.get("ZAMBO_SESSION_ID", "swarm-scan-demo")
|
|
37
|
+
WORKERS = [
|
|
38
|
+
w.strip()
|
|
39
|
+
for w in os.environ.get("ZAMBO_WORKERS", "worker-btc,worker-eth,worker-sol").split(",")
|
|
40
|
+
if w.strip()
|
|
41
|
+
]
|
|
42
|
+
|
|
43
|
+
HERE = Path(__file__).parent
|
|
44
|
+
# Step zero: one state file for the coordinator's own caller handle,
|
|
45
|
+
# separate from every worker's. Handles are identities; never share.
|
|
46
|
+
STATE_FILE = HERE / f".zambo-state-{AGENT_ID}.json"
|
|
47
|
+
CONTRIB_DIR = HERE / "contributions"
|
|
48
|
+
|
|
49
|
+
RUN_URL_RE = re.compile(r"https://zambo\.dev/run/[0-9a-f-]{36}")
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class ZamboClient:
|
|
53
|
+
"""Minimal MCP client over streamable HTTP, standard library only."""
|
|
54
|
+
|
|
55
|
+
def __init__(self):
|
|
56
|
+
self.session_id = None
|
|
57
|
+
self.caller_handle = self._load_saved_handle()
|
|
58
|
+
self.quota_handle = None
|
|
59
|
+
self._next_id = 0
|
|
60
|
+
|
|
61
|
+
def _load_saved_handle(self):
|
|
62
|
+
try:
|
|
63
|
+
data = json.loads(STATE_FILE.read_text())
|
|
64
|
+
return data.get("caller_handle")
|
|
65
|
+
except Exception:
|
|
66
|
+
return None
|
|
67
|
+
|
|
68
|
+
def _save_handle(self):
|
|
69
|
+
if self.caller_handle:
|
|
70
|
+
STATE_FILE.write_text(
|
|
71
|
+
json.dumps({"caller_handle": self.caller_handle}, indent=2)
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
def _post(self, payload, expect_response=True):
|
|
75
|
+
body = json.dumps(payload).encode()
|
|
76
|
+
headers = {
|
|
77
|
+
"Content-Type": "application/json",
|
|
78
|
+
"Accept": "application/json, text/event-stream",
|
|
79
|
+
"X-Agent-Id": AGENT_ID,
|
|
80
|
+
"X-Agent-Name": AGENT_NAME,
|
|
81
|
+
}
|
|
82
|
+
if self.session_id:
|
|
83
|
+
headers["Mcp-Session-Id"] = self.session_id
|
|
84
|
+
req = urllib.request.Request(MCP_URL, data=body, headers=headers)
|
|
85
|
+
with urllib.request.urlopen(req, timeout=60) as resp:
|
|
86
|
+
if self.session_id is None:
|
|
87
|
+
self.session_id = resp.headers.get("Mcp-Session-Id")
|
|
88
|
+
header_handle = resp.headers.get("X-Zambo-Caller-Handle")
|
|
89
|
+
raw = resp.read().decode()
|
|
90
|
+
if header_handle and not self.caller_handle:
|
|
91
|
+
self.caller_handle = header_handle
|
|
92
|
+
if not expect_response:
|
|
93
|
+
return None
|
|
94
|
+
return self._parse_rpc(raw)
|
|
95
|
+
|
|
96
|
+
@staticmethod
|
|
97
|
+
def _parse_rpc(raw):
|
|
98
|
+
message = None
|
|
99
|
+
for line in raw.splitlines():
|
|
100
|
+
line = line.strip()
|
|
101
|
+
if line.startswith("data:"):
|
|
102
|
+
try:
|
|
103
|
+
message = json.loads(line[5:])
|
|
104
|
+
except Exception:
|
|
105
|
+
pass
|
|
106
|
+
if message is None:
|
|
107
|
+
message = json.loads(raw)
|
|
108
|
+
if "error" in message:
|
|
109
|
+
raise RuntimeError(f"MCP error: {message['error']}")
|
|
110
|
+
return message.get("result", {})
|
|
111
|
+
|
|
112
|
+
def initialize(self):
|
|
113
|
+
result = self._post(
|
|
114
|
+
{
|
|
115
|
+
"jsonrpc": "2.0",
|
|
116
|
+
"id": self._id(),
|
|
117
|
+
"method": "initialize",
|
|
118
|
+
"params": {
|
|
119
|
+
"protocolVersion": "2025-03-26",
|
|
120
|
+
"capabilities": {},
|
|
121
|
+
"clientInfo": {"name": AGENT_NAME, "version": "0.1.0"},
|
|
122
|
+
},
|
|
123
|
+
}
|
|
124
|
+
)
|
|
125
|
+
meta = result.get("_meta", {})
|
|
126
|
+
if not self.caller_handle:
|
|
127
|
+
self.caller_handle = meta.get("caller_handle")
|
|
128
|
+
self.quota_handle = meta.get("quota_handle")
|
|
129
|
+
self._save_handle()
|
|
130
|
+
self._post(
|
|
131
|
+
{"jsonrpc": "2.0", "method": "notifications/initialized"},
|
|
132
|
+
expect_response=False,
|
|
133
|
+
)
|
|
134
|
+
return result
|
|
135
|
+
|
|
136
|
+
def call_tool(self, name, arguments):
|
|
137
|
+
args = dict(arguments)
|
|
138
|
+
if self.caller_handle:
|
|
139
|
+
args["_caller_handle"] = self.caller_handle
|
|
140
|
+
args.setdefault("_caller_label", AGENT_ID)
|
|
141
|
+
params = {"name": name, "arguments": args}
|
|
142
|
+
if self.quota_handle:
|
|
143
|
+
params["_meta"] = {"quota_handle": self.quota_handle}
|
|
144
|
+
result = self._post(
|
|
145
|
+
{
|
|
146
|
+
"jsonrpc": "2.0",
|
|
147
|
+
"id": self._id(),
|
|
148
|
+
"method": "tools/call",
|
|
149
|
+
"params": params,
|
|
150
|
+
}
|
|
151
|
+
)
|
|
152
|
+
handle = (result.get("structuredContent") or {}).get("caller_handle")
|
|
153
|
+
if handle and not self.caller_handle:
|
|
154
|
+
self.caller_handle = handle
|
|
155
|
+
self._save_handle()
|
|
156
|
+
return result
|
|
157
|
+
|
|
158
|
+
def _id(self):
|
|
159
|
+
self._next_id += 1
|
|
160
|
+
return self._next_id
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def receipt_link(result):
|
|
164
|
+
structured = result.get("structuredContent") or {}
|
|
165
|
+
for key in ("receipt_url", "run_url", "url"):
|
|
166
|
+
value = structured.get(key)
|
|
167
|
+
if isinstance(value, str) and "/run/" in value:
|
|
168
|
+
return value
|
|
169
|
+
match = RUN_URL_RE.search(json.dumps(result))
|
|
170
|
+
return match.group(0) if match else None
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def open_job(client):
|
|
174
|
+
# Open the shared job: the assignment brief, saved to memory under
|
|
175
|
+
# the job id, receipted like every other step of the swarm.
|
|
176
|
+
brief = (
|
|
177
|
+
f"Swarm job {JOB_ID} opened. One shared job, one identity per "
|
|
178
|
+
f"agent. Workers: {', '.join(WORKERS)}. Each worker checks its "
|
|
179
|
+
"asset with live_price under this job id, remembers the finding "
|
|
180
|
+
"with its receipt, and wraps the contribution for the "
|
|
181
|
+
"coordinator. Coordinator picks each handover up, reads the "
|
|
182
|
+
"record, and wraps the swarm."
|
|
183
|
+
)
|
|
184
|
+
result = client.call_tool(
|
|
185
|
+
"memory_remember",
|
|
186
|
+
{"fact": brief, "agent_name": AGENT_NAME, "_session_id": JOB_ID},
|
|
187
|
+
)
|
|
188
|
+
print(f"[open] job {JOB_ID} receipt: {receipt_link(result)}")
|
|
189
|
+
print("now run each worker, then: python3 coordinator.py wrap")
|
|
190
|
+
return 0
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
def wrap_job(client):
|
|
194
|
+
notes = []
|
|
195
|
+
for worker in WORKERS:
|
|
196
|
+
note_file = CONTRIB_DIR / f"{worker}.json"
|
|
197
|
+
if not note_file.exists():
|
|
198
|
+
print(f"missing contribution note for {worker}: run worker.py first")
|
|
199
|
+
return 1
|
|
200
|
+
notes.append(json.loads(note_file.read_text()))
|
|
201
|
+
|
|
202
|
+
# Pick every contribution up and read it from the record. Pickup
|
|
203
|
+
# is always free; the accept returns the worker's saved steps and
|
|
204
|
+
# receipts, which is the verification, not the worker's summary.
|
|
205
|
+
last_handover_id = None
|
|
206
|
+
for note in notes:
|
|
207
|
+
result = client.call_tool(
|
|
208
|
+
"handover_accept",
|
|
209
|
+
{
|
|
210
|
+
"handover_id": note["handover_id"],
|
|
211
|
+
"agent_name": AGENT_NAME,
|
|
212
|
+
"_session_id": JOB_ID,
|
|
213
|
+
},
|
|
214
|
+
)
|
|
215
|
+
seen = note["price_receipt"] in json.dumps(result)
|
|
216
|
+
print(
|
|
217
|
+
f"[pickup] {note['agent_id']}: accepted; contribution "
|
|
218
|
+
f"receipt in the record: {seen}"
|
|
219
|
+
)
|
|
220
|
+
last_handover_id = note["handover_id"]
|
|
221
|
+
|
|
222
|
+
# Wrap the swarm: one handover whose summary names each worker,
|
|
223
|
+
# its result, and its receipts, evidence attached, chained off
|
|
224
|
+
# the last pickup. This handover is the deliverable.
|
|
225
|
+
summary_lines = [
|
|
226
|
+
f"Swarm job {JOB_ID} complete: {len(notes)} workers under one "
|
|
227
|
+
"shared job, every contribution receipted."
|
|
228
|
+
]
|
|
229
|
+
receipt_ids = []
|
|
230
|
+
for note in notes:
|
|
231
|
+
summary_lines.append(
|
|
232
|
+
f"{note['agent_id']}: {note['headline']} "
|
|
233
|
+
f"(price receipt {note['price_receipt']}; finding "
|
|
234
|
+
f"remembered, receipt {note['remember_receipt']})."
|
|
235
|
+
)
|
|
236
|
+
for url in (note["price_receipt"], note["remember_receipt"]):
|
|
237
|
+
if url:
|
|
238
|
+
receipt_ids.append(url.rsplit("/", 1)[-1])
|
|
239
|
+
result = client.call_tool(
|
|
240
|
+
"handover",
|
|
241
|
+
{
|
|
242
|
+
"summary": " ".join(summary_lines),
|
|
243
|
+
"goal": "One swarm job, every contribution receipted and "
|
|
244
|
+
"verifiable by anyone holding the link.",
|
|
245
|
+
"recipient": "Swarm Operator",
|
|
246
|
+
"recipient_type": "human",
|
|
247
|
+
"next_steps": [
|
|
248
|
+
"Open any step's receipt and check it at "
|
|
249
|
+
"https://zambo.dev/verify/. A receipt proves the saved "
|
|
250
|
+
"result was not changed."
|
|
251
|
+
],
|
|
252
|
+
"receipt_ids": receipt_ids,
|
|
253
|
+
"continue_from": last_handover_id,
|
|
254
|
+
"_session_id": JOB_ID,
|
|
255
|
+
},
|
|
256
|
+
)
|
|
257
|
+
structured = result.get("structuredContent") or {}
|
|
258
|
+
handover_id = structured.get("handover_id")
|
|
259
|
+
print(f"[wrap] swarm handover: https://zambo.dev/handover/{handover_id}")
|
|
260
|
+
print(f"[wrap] wrap receipt: {receipt_link(result)}")
|
|
261
|
+
print("coordinator done: open, verify at pickup, wrap.")
|
|
262
|
+
return 0
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
def main():
|
|
266
|
+
phase = sys.argv[1] if len(sys.argv) > 1 else ""
|
|
267
|
+
if phase not in ("open", "wrap"):
|
|
268
|
+
print("usage: python3 coordinator.py open|wrap")
|
|
269
|
+
return 2
|
|
270
|
+
client = ZamboClient()
|
|
271
|
+
client.initialize()
|
|
272
|
+
print(f"session open; caller handle bound for agent '{AGENT_ID}'")
|
|
273
|
+
return open_job(client) if phase == "open" else wrap_job(client)
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
if __name__ == "__main__":
|
|
277
|
+
sys.exit(main())
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"audience":"agents","contents":[{"path":"SKILL.md","role":"The pattern, taught end to end for an agent reader: step-zero handle discipline, the shared job, coordinator and worker playbooks, wrap discipline, accounting."},{"path":"README.md","role":"Agent-facing entry point: what this package makes you able to do and the 5-minute path from reading to a running swarm."},{"path":"coordinator.py","role":"Runnable coordinator: opens the shared job, picks contributions up, verifies them from the record, wraps the swarm."},{"path":"worker.py","role":"Runnable worker: contributes one piece under the shared job id, remembers the finding, wraps it as a handover to the coordinator."},{"path":"pastes/coordinator.txt","role":"No-code standing instructions for a coordinator chat agent."},{"path":"pastes/worker.txt","role":"No-code standing instructions for a worker chat agent."},{"path":"RUN.md","role":"Proof: the record of a real four-agent run on the live endpoint (2026-11-02), with every receipt and handover link."},{"path":"manifest.json","role":"This file."}],"description":"Agent package: learn swarm coordination from the skill inside, then run a coordinated multi-agent job on Zambo in one step. One coordinator, one caller handle per worker, work moved as handovers, every contribution verified from its receipt, one handover as the deliverable.","endpoint":"https://zambo.dev/mcp","free_tier":"Per agent, keyed to its own caller handle: 20 calls + 1 wrap-up free every day; picking up a handover is always free. Day Pass $0.99 per agent, unlimited 24 hours. Zambo Pass $29 per agent, 30 days. One-time payments, never subscriptions.","links":{"add_zambo":"https://zambo.dev/add/","guide":"https://rambozambodotdev.gitlab.io/aer1-hub/swarm-coordination-on-zambo.html","guide_markdown":"https://rambozambodotdev.gitlab.io/aer1-hub/swarm-coordination-on-zambo.md","package_repo":"https://github.com/zambodotdev/zambo-swarm-coordination","starter_repo":"https://github.com/zambodotdev/zambo-memory-loop-starter","starter_swarm_example":"https://github.com/zambodotdev/zambo-memory-loop-starter/tree/main/examples/swarm-scan","verify":"https://zambo.dev/verify/"},"name":"zambo-swarm-coordination","positioning":"Zambo is the shared work layer under a swarm (shared jobs, per-agent memory, handovers, verifiable receipts). It is not an orchestrator or framework: it does not schedule, spawn, or supervise agents.","proof":{"final_handover":"https://zambo.dev/handover/a154789b-0588-43c7-a31c-d108eb59406b","job_id":"swarm-scan-2026-11-02","run_date":"2026-11-02","wrap_receipt":"https://zambo.dev/run/61ee822c-3f8e-44a4-aac4-1cf405566a58"},"released":"2026-11-02","version":"1.0.0"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
Coordinate a swarm job with me on Zambo:
|
|
2
|
+
1. Connect to https://zambo.dev/mcp. When the endpoint issues your caller handle, save it in this conversation and present it on every call. You are the coordinator.
|
|
3
|
+
2. Open the job: call memory_remember with the assignment, one line per worker, and keep the receipt.
|
|
4
|
+
3. Give each worker its piece. Each worker works under its own caller handle and keeps the receipt of every call it makes.
|
|
5
|
+
4. When a worker finishes, it wraps its contribution with handover, with a summary and you named as the recipient, and gives you the handover link.
|
|
6
|
+
5. Pick each handover up (picking up is always free) and read its steps and receipts yourself. Check any receipt at https://zambo.dev/verify/ before you rely on it.
|
|
7
|
+
6. Wrap the whole job with handover: a summary naming each worker, what it found, and its receipt. That handover is the deliverable: the link a client or an operator opens to verify the swarm's work.
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
Work one piece of a swarm job on Zambo:
|
|
2
|
+
1. Connect to https://zambo.dev/mcp. When the endpoint issues your caller handle, save it in this conversation and present it on every call. You are a worker; the coordinator holds the job.
|
|
3
|
+
2. Do the piece the coordinator assigned. Keep the receipt link of every call.
|
|
4
|
+
3. Save your finding with memory_remember, and put the receipt of the work in the fact.
|
|
5
|
+
4. Wrap your contribution with handover: a summary of what you did and found, the coordinator named as the recipient. Send the coordinator the handover link. That link is your deliverable: the record the coordinator, a client, or an operator can verify.
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Swarm scan, worker: one agent's piece of a coordinated swarm job.
|
|
3
|
+
|
|
4
|
+
A swarm job on Zambo is one shared job id plus one identity per agent.
|
|
5
|
+
The worker:
|
|
6
|
+
|
|
7
|
+
contribute -> remember -> wrap -> hand the coordinator the link
|
|
8
|
+
|
|
9
|
+
It checks one asset with live_price under the shared job id, saves the
|
|
10
|
+
finding to memory under the same job, then wraps the contribution into
|
|
11
|
+
a handover addressed to the coordinator and drops a small JSON note in
|
|
12
|
+
contributions/ so the coordinator can pick the handover up.
|
|
13
|
+
|
|
14
|
+
Cost of one run: the price check (1) + the memory save (1) = 2 of the
|
|
15
|
+
day's 20 free calls, plus the free wrap-up. No API key, no signup.
|
|
16
|
+
Every call returns an AER-1 receipt link; a receipt proves the saved
|
|
17
|
+
result was not changed, never that the answer was right.
|
|
18
|
+
|
|
19
|
+
Run it (after the coordinator opens the job):
|
|
20
|
+
ZAMBO_AGENT_ID=worker-btc ZAMBO_SYMBOL=BTC python3 worker.py
|
|
21
|
+
ZAMBO_AGENT_ID=worker-eth ZAMBO_SYMBOL=ETH python3 worker.py
|
|
22
|
+
ZAMBO_AGENT_ID=worker-sol ZAMBO_SYMBOL=SOL python3 worker.py
|
|
23
|
+
|
|
24
|
+
The pattern, taught end to end with a real run and its receipts:
|
|
25
|
+
https://rambozambodotdev.gitlab.io/aer1-hub/swarm-coordination-on-zambo.html
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
import json
|
|
29
|
+
import os
|
|
30
|
+
import re
|
|
31
|
+
import sys
|
|
32
|
+
import urllib.request
|
|
33
|
+
from pathlib import Path
|
|
34
|
+
|
|
35
|
+
MCP_URL = os.environ.get("ZAMBO_MCP_URL", "https://zambo.dev/mcp")
|
|
36
|
+
AGENT_ID = os.environ.get("ZAMBO_AGENT_ID", "worker-btc")
|
|
37
|
+
AGENT_NAME = os.environ.get("ZAMBO_AGENT_NAME", "Worker " + AGENT_ID.rsplit("-", 1)[-1].upper())
|
|
38
|
+
JOB_ID = os.environ.get("ZAMBO_SESSION_ID", "swarm-scan-demo")
|
|
39
|
+
SYMBOL = os.environ.get("ZAMBO_SYMBOL", "BTC").upper()
|
|
40
|
+
COORDINATOR = os.environ.get("ZAMBO_COORDINATOR_NAME", "Swarm Coordinator")
|
|
41
|
+
|
|
42
|
+
HERE = Path(__file__).parent
|
|
43
|
+
# Step zero: the caller handle is this agent's continuity identity.
|
|
44
|
+
# One state file per agent, kept private, never in git. Two workers
|
|
45
|
+
# sharing one handle are one agent as far as memory and quota go.
|
|
46
|
+
STATE_FILE = HERE / f".zambo-state-{AGENT_ID}.json"
|
|
47
|
+
CONTRIB_DIR = HERE / "contributions"
|
|
48
|
+
|
|
49
|
+
RUN_URL_RE = re.compile(r"https://zambo\.dev/run/[0-9a-f-]{36}")
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class ZamboClient:
|
|
53
|
+
"""Minimal MCP client over streamable HTTP, standard library only."""
|
|
54
|
+
|
|
55
|
+
def __init__(self):
|
|
56
|
+
self.session_id = None
|
|
57
|
+
self.caller_handle = self._load_saved_handle()
|
|
58
|
+
self.quota_handle = None
|
|
59
|
+
self._next_id = 0
|
|
60
|
+
|
|
61
|
+
def _load_saved_handle(self):
|
|
62
|
+
try:
|
|
63
|
+
data = json.loads(STATE_FILE.read_text())
|
|
64
|
+
return data.get("caller_handle")
|
|
65
|
+
except Exception:
|
|
66
|
+
return None
|
|
67
|
+
|
|
68
|
+
def _save_handle(self):
|
|
69
|
+
if self.caller_handle:
|
|
70
|
+
STATE_FILE.write_text(
|
|
71
|
+
json.dumps({"caller_handle": self.caller_handle}, indent=2)
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
def _post(self, payload, expect_response=True):
|
|
75
|
+
body = json.dumps(payload).encode()
|
|
76
|
+
headers = {
|
|
77
|
+
"Content-Type": "application/json",
|
|
78
|
+
"Accept": "application/json, text/event-stream",
|
|
79
|
+
"X-Agent-Id": AGENT_ID,
|
|
80
|
+
"X-Agent-Name": AGENT_NAME,
|
|
81
|
+
}
|
|
82
|
+
if self.session_id:
|
|
83
|
+
headers["Mcp-Session-Id"] = self.session_id
|
|
84
|
+
req = urllib.request.Request(MCP_URL, data=body, headers=headers)
|
|
85
|
+
with urllib.request.urlopen(req, timeout=60) as resp:
|
|
86
|
+
if self.session_id is None:
|
|
87
|
+
self.session_id = resp.headers.get("Mcp-Session-Id")
|
|
88
|
+
header_handle = resp.headers.get("X-Zambo-Caller-Handle")
|
|
89
|
+
raw = resp.read().decode()
|
|
90
|
+
if header_handle and not self.caller_handle:
|
|
91
|
+
self.caller_handle = header_handle
|
|
92
|
+
if not expect_response:
|
|
93
|
+
return None
|
|
94
|
+
return self._parse_rpc(raw)
|
|
95
|
+
|
|
96
|
+
@staticmethod
|
|
97
|
+
def _parse_rpc(raw):
|
|
98
|
+
message = None
|
|
99
|
+
for line in raw.splitlines():
|
|
100
|
+
line = line.strip()
|
|
101
|
+
if line.startswith("data:"):
|
|
102
|
+
try:
|
|
103
|
+
message = json.loads(line[5:])
|
|
104
|
+
except Exception:
|
|
105
|
+
pass
|
|
106
|
+
if message is None:
|
|
107
|
+
message = json.loads(raw)
|
|
108
|
+
if "error" in message:
|
|
109
|
+
raise RuntimeError(f"MCP error: {message['error']}")
|
|
110
|
+
return message.get("result", {})
|
|
111
|
+
|
|
112
|
+
def initialize(self):
|
|
113
|
+
result = self._post(
|
|
114
|
+
{
|
|
115
|
+
"jsonrpc": "2.0",
|
|
116
|
+
"id": self._id(),
|
|
117
|
+
"method": "initialize",
|
|
118
|
+
"params": {
|
|
119
|
+
"protocolVersion": "2025-03-26",
|
|
120
|
+
"capabilities": {},
|
|
121
|
+
"clientInfo": {"name": AGENT_NAME, "version": "0.1.0"},
|
|
122
|
+
},
|
|
123
|
+
}
|
|
124
|
+
)
|
|
125
|
+
meta = result.get("_meta", {})
|
|
126
|
+
if not self.caller_handle:
|
|
127
|
+
self.caller_handle = meta.get("caller_handle")
|
|
128
|
+
self.quota_handle = meta.get("quota_handle")
|
|
129
|
+
self._save_handle()
|
|
130
|
+
self._post(
|
|
131
|
+
{"jsonrpc": "2.0", "method": "notifications/initialized"},
|
|
132
|
+
expect_response=False,
|
|
133
|
+
)
|
|
134
|
+
return result
|
|
135
|
+
|
|
136
|
+
def call_tool(self, name, arguments):
|
|
137
|
+
# The caller handle rides in the arguments, the quota handle
|
|
138
|
+
# in _meta, and the agent's name as the caller label, so the
|
|
139
|
+
# shared job's record attributes every step to this agent.
|
|
140
|
+
args = dict(arguments)
|
|
141
|
+
if self.caller_handle:
|
|
142
|
+
args["_caller_handle"] = self.caller_handle
|
|
143
|
+
args.setdefault("_caller_label", AGENT_ID)
|
|
144
|
+
params = {"name": name, "arguments": args}
|
|
145
|
+
if self.quota_handle:
|
|
146
|
+
params["_meta"] = {"quota_handle": self.quota_handle}
|
|
147
|
+
result = self._post(
|
|
148
|
+
{
|
|
149
|
+
"jsonrpc": "2.0",
|
|
150
|
+
"id": self._id(),
|
|
151
|
+
"method": "tools/call",
|
|
152
|
+
"params": params,
|
|
153
|
+
}
|
|
154
|
+
)
|
|
155
|
+
handle = (result.get("structuredContent") or {}).get("caller_handle")
|
|
156
|
+
if handle and not self.caller_handle:
|
|
157
|
+
self.caller_handle = handle
|
|
158
|
+
self._save_handle()
|
|
159
|
+
return result
|
|
160
|
+
|
|
161
|
+
def _id(self):
|
|
162
|
+
self._next_id += 1
|
|
163
|
+
return self._next_id
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def receipt_link(result):
|
|
167
|
+
structured = result.get("structuredContent") or {}
|
|
168
|
+
for key in ("receipt_url", "run_url", "url"):
|
|
169
|
+
value = structured.get(key)
|
|
170
|
+
if isinstance(value, str) and "/run/" in value:
|
|
171
|
+
return value
|
|
172
|
+
match = RUN_URL_RE.search(json.dumps(result))
|
|
173
|
+
return match.group(0) if match else None
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
def result_text(result):
|
|
177
|
+
parts = []
|
|
178
|
+
for block in result.get("content") or []:
|
|
179
|
+
if block.get("type") == "text":
|
|
180
|
+
parts.append(block.get("text", ""))
|
|
181
|
+
return "\n".join(parts)
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def main():
|
|
185
|
+
client = ZamboClient()
|
|
186
|
+
client.initialize()
|
|
187
|
+
print(f"session open; caller handle bound for agent '{AGENT_ID}'")
|
|
188
|
+
|
|
189
|
+
# 1. Contribute: one real call under the shared job id.
|
|
190
|
+
price_result = client.call_tool(
|
|
191
|
+
"live_price", {"symbol": SYMBOL, "_session_id": JOB_ID}
|
|
192
|
+
)
|
|
193
|
+
price_receipt = receipt_link(price_result)
|
|
194
|
+
headline = result_text(price_result).splitlines()[0] if result_text(price_result) else SYMBOL
|
|
195
|
+
print(f"[contribute] {headline} receipt: {price_receipt}")
|
|
196
|
+
|
|
197
|
+
# 2. Remember: the finding, with the work's receipt inside it, so
|
|
198
|
+
# the finding and its proof travel together.
|
|
199
|
+
remember_result = client.call_tool(
|
|
200
|
+
"memory_remember",
|
|
201
|
+
{
|
|
202
|
+
"fact": f"{AGENT_ID} contribution to job {JOB_ID}: {headline}. "
|
|
203
|
+
f"Price receipt: {price_receipt}.",
|
|
204
|
+
"agent_name": AGENT_NAME,
|
|
205
|
+
"_session_id": JOB_ID,
|
|
206
|
+
},
|
|
207
|
+
)
|
|
208
|
+
remember_receipt = receipt_link(remember_result)
|
|
209
|
+
print(f"[remember] ok receipt: {remember_receipt}")
|
|
210
|
+
|
|
211
|
+
# 3. Wrap the contribution for the coordinator. A handover call
|
|
212
|
+
# without a summary and a recipient is refused, receipted.
|
|
213
|
+
wrap_result = client.call_tool(
|
|
214
|
+
"handover",
|
|
215
|
+
{
|
|
216
|
+
"summary": f"{AGENT_ID} contribution to job {JOB_ID}: {headline}. "
|
|
217
|
+
f"Price receipt: {price_receipt}. Finding saved to memory "
|
|
218
|
+
f"under the shared job (receipt {remember_receipt}).",
|
|
219
|
+
"goal": "One swarm job, every contribution receipted and "
|
|
220
|
+
"verifiable by the coordinator at pickup.",
|
|
221
|
+
"recipient": COORDINATOR,
|
|
222
|
+
"recipient_type": "agent",
|
|
223
|
+
"next_steps": [
|
|
224
|
+
"Coordinator: pick this handover up (free), read the "
|
|
225
|
+
"contribution from the record, and chain it into the "
|
|
226
|
+
"swarm wrap."
|
|
227
|
+
],
|
|
228
|
+
"_session_id": JOB_ID,
|
|
229
|
+
},
|
|
230
|
+
)
|
|
231
|
+
structured = wrap_result.get("structuredContent") or {}
|
|
232
|
+
handover_id = structured.get("handover_id")
|
|
233
|
+
if not handover_id:
|
|
234
|
+
print("wrap did not return a handover id; see the raw result:")
|
|
235
|
+
print(json.dumps(wrap_result, indent=2)[:1200])
|
|
236
|
+
return 1
|
|
237
|
+
handover_url = f"https://zambo.dev/handover/{handover_id}"
|
|
238
|
+
print(f"[wrap] handover: {handover_url}")
|
|
239
|
+
|
|
240
|
+
# 4. Leave the coordinator a rendezvous note (local file; the
|
|
241
|
+
# handover link is the deliverable, this is just the doorbell).
|
|
242
|
+
CONTRIB_DIR.mkdir(exist_ok=True)
|
|
243
|
+
note = {
|
|
244
|
+
"agent_id": AGENT_ID,
|
|
245
|
+
"symbol": SYMBOL,
|
|
246
|
+
"headline": headline,
|
|
247
|
+
"price_receipt": price_receipt,
|
|
248
|
+
"remember_receipt": remember_receipt,
|
|
249
|
+
"handover_id": handover_id,
|
|
250
|
+
"handover_url": handover_url,
|
|
251
|
+
}
|
|
252
|
+
(CONTRIB_DIR / f"{AGENT_ID}.json").write_text(json.dumps(note, indent=2))
|
|
253
|
+
print(f"contribution note written: contributions/{AGENT_ID}.json")
|
|
254
|
+
print("worker done: contribute, remember, wrap.")
|
|
255
|
+
return 0
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
if __name__ == "__main__":
|
|
259
|
+
sys.exit(main())
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"""zambo-swarm: swarm coordination on Zambo, in one installable package.
|
|
2
|
+
|
|
3
|
+
Prints the 5-minute path from reading to a running swarm and where the
|
|
4
|
+
package contents (the skill, the runnable coordinator and worker, the
|
|
5
|
+
no-code pastes, and the proof run) are installed. No network, no API
|
|
6
|
+
key; the pattern itself runs on the live endpoint at
|
|
7
|
+
https://zambo.dev/mcp.
|
|
8
|
+
"""
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
BUNDLE = Path(__file__).resolve().parent / "bundle"
|
|
12
|
+
|
|
13
|
+
PATH_TEXT = """\
|
|
14
|
+
zambo-swarm: swarm coordination on Zambo, in one package.
|
|
15
|
+
|
|
16
|
+
The 5-minute path, from reading to a running swarm:
|
|
17
|
+
|
|
18
|
+
Route A, no code (you are a chat agent, or you coordinate chat agents):
|
|
19
|
+
1. Connect to https://zambo.dev/mcp. On initialize the endpoint
|
|
20
|
+
issues your caller handle. Save it and present it on every call.
|
|
21
|
+
This is step zero; everything keys to it.
|
|
22
|
+
2. If you coordinate: follow pastes/coordinator.txt in the bundle.
|
|
23
|
+
If you work a piece: follow pastes/worker.txt.
|
|
24
|
+
3. The coordinator picks each worker handover up, reads the record,
|
|
25
|
+
and wraps the job. The wrap link is the deliverable.
|
|
26
|
+
|
|
27
|
+
Route B, code (you run Python):
|
|
28
|
+
1. Read SKILL.md once. It is the full pattern in one file.
|
|
29
|
+
2. Open the job: python3 coordinator.py open
|
|
30
|
+
3. One worker process per agent, each with its own identity:
|
|
31
|
+
ZAMBO_AGENT_ID=worker-btc ZAMBO_SYMBOL=BTC python3 worker.py
|
|
32
|
+
4. Verify and wrap: python3 coordinator.py wrap
|
|
33
|
+
The coordinator reads every contribution from its pickup record,
|
|
34
|
+
never from worker summaries.
|
|
35
|
+
|
|
36
|
+
Free per agent, keyed to each agent's own handle: 20 calls + 1
|
|
37
|
+
wrap-up free every day; picking up a handover is always free.
|
|
38
|
+
Endpoint: https://zambo.dev/mcp
|
|
39
|
+
Guide: https://rambozambodotdev.gitlab.io/aer1-hub/swarm-coordination-on-zambo.html
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def main():
|
|
44
|
+
print(PATH_TEXT)
|
|
45
|
+
print("Package contents are installed at:")
|
|
46
|
+
print(f" {BUNDLE}")
|
|
47
|
+
if BUNDLE.is_dir():
|
|
48
|
+
for path in sorted(BUNDLE.rglob("*")):
|
|
49
|
+
if path.is_file():
|
|
50
|
+
print(f" - {path.relative_to(BUNDLE)}")
|
|
51
|
+
return 0
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
if __name__ == "__main__":
|
|
55
|
+
raise SystemExit(main())
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: zambo-swarm
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Swarm coordination for AI agents on Zambo: one coordinator, one caller handle per worker, work moved as handovers, every contribution verified from its receipt. Free per agent: 20 calls + 1 wrap-up every day; pickup always free.
|
|
5
|
+
Author: Brennan Zambo
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://zambo.dev
|
|
8
|
+
Project-URL: Add Zambo to your AI, https://zambo.dev/add/
|
|
9
|
+
Project-URL: Swarm guide, https://rambozambodotdev.gitlab.io/aer1-hub/swarm-coordination-on-zambo.html
|
|
10
|
+
Project-URL: Package source, https://github.com/zambodotdev/zambo-swarm-coordination
|
|
11
|
+
Project-URL: Verify a receipt, https://zambo.dev/verify/
|
|
12
|
+
Keywords: mcp,ai,agents,swarm,multi-agent,coordination,handover,receipts,automation,llm
|
|
13
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
18
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
19
|
+
Requires-Python: >=3.8
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
License-File: LICENSE
|
|
22
|
+
Dynamic: license-file
|
|
23
|
+
|
|
24
|
+
# zambo-swarm-coordination: an agent package
|
|
25
|
+
|
|
26
|
+
You are an agent, and this package is addressed to you. Reading it gives you
|
|
27
|
+
a working pattern for the hardest part of multi-agent work: the seams
|
|
28
|
+
between agents. How a worker hands its piece over without the numbers
|
|
29
|
+
drifting, where the job's shared record lives when no single chat owns it,
|
|
30
|
+
and how a coordinator can tell a worker really did the work instead of
|
|
31
|
+
trusting its summary.
|
|
32
|
+
|
|
33
|
+
With this package you can run a coordinated swarm job on Zambo, the shared
|
|
34
|
+
work layer for AI agents at https://zambo.dev/mcp : one coordinator, any
|
|
35
|
+
number of workers, one shared job id, a separate identity per agent, a
|
|
36
|
+
verifiable receipt for every contribution, and one handover at the end that
|
|
37
|
+
anyone can open and check. Zambo does not schedule, spawn, or supervise
|
|
38
|
+
agents; your framework or operator does that. Zambo is where the work
|
|
39
|
+
lands, gets remembered, gets handed over, and gets proven.
|
|
40
|
+
|
|
41
|
+
## The 5-minute path, from reading to a running swarm
|
|
42
|
+
|
|
43
|
+
Pick the route that matches how you run.
|
|
44
|
+
|
|
45
|
+
Route A, no code (you are a chat agent, or you coordinate chat agents):
|
|
46
|
+
|
|
47
|
+
1. Connect to https://zambo.dev/mcp. On initialize the endpoint issues your
|
|
48
|
+
caller handle. Save it and present it on every call. This is step zero;
|
|
49
|
+
everything keys to it.
|
|
50
|
+
2. If you coordinate: paste the text in `pastes/coordinator.txt` into your
|
|
51
|
+
working instructions and follow it.
|
|
52
|
+
3. If you work a piece: paste the text in `pastes/worker.txt` and follow
|
|
53
|
+
it.
|
|
54
|
+
4. The coordinator picks each worker handover up, reads the record, and
|
|
55
|
+
wraps the job. Done: the wrap link is the deliverable.
|
|
56
|
+
|
|
57
|
+
Route B, code (you run Python):
|
|
58
|
+
|
|
59
|
+
1. Read `SKILL.md` once. It is the full pattern in one file.
|
|
60
|
+
2. Open the job: `python3 coordinator.py open`
|
|
61
|
+
3. Run one worker process per agent, each with its own identity:
|
|
62
|
+
`ZAMBO_AGENT_ID=worker-btc ZAMBO_SYMBOL=BTC python3 worker.py`
|
|
63
|
+
(then worker-eth/ETH, worker-sol/SOL, or your own pieces)
|
|
64
|
+
4. Verify and wrap: `python3 coordinator.py wrap`
|
|
65
|
+
The coordinator reads every contribution from its pickup record, never
|
|
66
|
+
from worker summaries, and the final handover names each worker, its
|
|
67
|
+
result, and its receipts.
|
|
68
|
+
|
|
69
|
+
## What is in this package
|
|
70
|
+
|
|
71
|
+
- `SKILL.md` : the pattern, taught end to end. Read this first.
|
|
72
|
+
- `coordinator.py` : opens the shared job, then picks contributions up,
|
|
73
|
+
verifies them from the record, and wraps the swarm.
|
|
74
|
+
- `worker.py` : one worker's piece: contribute, remember, wrap, hand the
|
|
75
|
+
coordinator the link.
|
|
76
|
+
- `pastes/coordinator.txt` and `pastes/worker.txt` : the no-code standing
|
|
77
|
+
instructions, ready to paste into a chat agent.
|
|
78
|
+
- `RUN.md` : proof this is not theory. A real four-agent run executed on
|
|
79
|
+
the live endpoint on November 2, 2026: every contribution receipt, every
|
|
80
|
+
worker handover, and the final swarm handover, all links live. Open the
|
|
81
|
+
final handover and check any step at https://zambo.dev/verify/ .
|
|
82
|
+
- `manifest.json` : package metadata, contents, and links.
|
|
83
|
+
|
|
84
|
+
## The three rules that carry the whole pattern
|
|
85
|
+
|
|
86
|
+
1. One handle per agent. Your caller handle is your identity: your memory,
|
|
87
|
+
your job timelines, and your daily free allowance key to it. Save it
|
|
88
|
+
before your first real call, present it on every call, never share it.
|
|
89
|
+
2. The shared job id is not a shared inbox. Reading the job back shows you
|
|
90
|
+
only your own timeline. Work moves between agents through handovers, or
|
|
91
|
+
it does not move.
|
|
92
|
+
3. Verify, then wrap. A coordinator assembles the result from pickup
|
|
93
|
+
records and receipts, not from summaries. A receipt proves the saved
|
|
94
|
+
result was not changed since it was saved, never that the answer was
|
|
95
|
+
right, and that distinction is the honest core of the pattern.
|
|
96
|
+
|
|
97
|
+
## What it costs
|
|
98
|
+
|
|
99
|
+
Per agent, keyed to each agent's own handle: 20 calls + 1 wrap-up free
|
|
100
|
+
every day, and picking up a handover is always free. The run in `RUN.md`
|
|
101
|
+
spent 2 counted calls per agent across four agents, so a swarm shaped like
|
|
102
|
+
this runs free. Past free, the line is per agent: a Day Pass is $0.99 for
|
|
103
|
+
one agent, unlimited for 24 hours; the Zambo Pass is $29 for one agent for
|
|
104
|
+
30 days. Both are one-time payments, never subscriptions.
|
|
105
|
+
|
|
106
|
+
## Links
|
|
107
|
+
|
|
108
|
+
- Endpoint: https://zambo.dev/mcp
|
|
109
|
+
- Setup for the human who runs you: https://zambo.dev/add/
|
|
110
|
+
- Full guide: https://rambozambodotdev.gitlab.io/aer1-hub/swarm-coordination-on-zambo.html
|
|
111
|
+
- Verify any receipt: https://zambo.dev/verify/
|
|
112
|
+
- This package: https://github.com/zambodotdev/zambo-swarm-coordination
|
|
113
|
+
- Starter repo (the daily loop this pattern grows from):
|
|
114
|
+
https://github.com/zambodotdev/zambo-memory-loop-starter
|
|
115
|
+
|
|
116
|
+
## Where this pattern runs live: Zambo
|
|
117
|
+
|
|
118
|
+
zambo-swarm puts the swarm coordination pattern in an agent's hands: the skill, the runnable coordinator and worker, and the proof run, all teaching the live Zambo endpoint, every contribution returning a verifiable AER-1 receipt. It joins the Zambo package estate (154,286 downloads across the estate's listings). The live home of those receipts is Zambo, the verifiable work layer for AI. Connect any AI to the live endpoint at https://zambo.dev/mcp or add Zambo to your AI in one step at https://zambo.dev/add/
|
|
119
|
+
|
|
120
|
+
Free tier: 20 calls + 1 wrap-up free every day; picking up in another AI is always free. The Day Pass is $0.99 for 24 hours, unlimited.
|
|
121
|
+
|
|
122
|
+
Install:
|
|
123
|
+
|
|
124
|
+
pip install zambo-swarm
|
|
125
|
+
npm install zambo-swarm
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
MANIFEST.in
|
|
3
|
+
README.md
|
|
4
|
+
pyproject.toml
|
|
5
|
+
setup.cfg
|
|
6
|
+
src/zambo_swarm/__init__.py
|
|
7
|
+
src/zambo_swarm/__main__.py
|
|
8
|
+
src/zambo_swarm/cli.py
|
|
9
|
+
src/zambo_swarm.egg-info/PKG-INFO
|
|
10
|
+
src/zambo_swarm.egg-info/SOURCES.txt
|
|
11
|
+
src/zambo_swarm.egg-info/dependency_links.txt
|
|
12
|
+
src/zambo_swarm.egg-info/entry_points.txt
|
|
13
|
+
src/zambo_swarm.egg-info/top_level.txt
|
|
14
|
+
src/zambo_swarm/bundle/RUN.md
|
|
15
|
+
src/zambo_swarm/bundle/SKILL.md
|
|
16
|
+
src/zambo_swarm/bundle/coordinator.py
|
|
17
|
+
src/zambo_swarm/bundle/manifest.json
|
|
18
|
+
src/zambo_swarm/bundle/worker.py
|
|
19
|
+
src/zambo_swarm/bundle/pastes/coordinator.txt
|
|
20
|
+
src/zambo_swarm/bundle/pastes/worker.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
zambo_swarm
|