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.
@@ -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,2 @@
1
+ graft src/zambo_swarm/bundle
2
+ include LICENSE README.md pyproject.toml
@@ -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,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,3 @@
1
+ """zambo-swarm: the swarm coordination package for Zambo."""
2
+
3
+ __version__ = "1.0.0"
@@ -0,0 +1,4 @@
1
+ from .cli import main
2
+
3
+ if __name__ == "__main__":
4
+ raise SystemExit(main())
@@ -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,2 @@
1
+ [console_scripts]
2
+ zambo-swarm = zambo_swarm.cli:main
@@ -0,0 +1 @@
1
+ zambo_swarm