Observed since 20 Oct, 16:33 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
Out-of-the-box NATS-based agent-to-agent (A2A) protocol and Python client.
A small Python package that gives you the boring parts of an A2A (agent-to-agent) protocol so you can focus on what your agents actually do:
Query / Reply / Ack / Discovery /
Pulse pydantic models, one canonical wire format. Every envelope
carries optional clock + host so receivers can anchor freshness
without trusting conversation history.<prefix>.<agent>.<verb>.<topic>, prefix
configurable per fleet, parseable both directions.AgentBus) — thin wrapper on nats-py with
publish auditing, a request/reply helper that dodges the core-NATS
"no-sub means lost" gotcha, and an InboundContext that handlers can
use to reply / ack without juggling state.ana) — listen / send / probe so shell scripts and
operators don't need to import Python.Built on top of existing NATS — bring your own cluster, anonymous or auth, core or JetStream. ana does not deploy anything.
pip install a2o-ana # PyPI distribution
# or, from source:
pip install -e .[dev]
(PyPI distribution is a2o-ana because the bare ana name was squatted in 2015.
The import name stays ana — from ana import AgentBus.)
import asyncio
from ana import AgentBus
async def main():
async with AgentBus("my-bot") as bus:
await bus.query("other-bot", "what's your status?")
asyncio.run(main())
import asyncio
from ana import AgentBus, Query
from ana.client import InboundContext
async def handler(env, ctx: InboundContext):
if isinstance(env, Query):
await ctx.reply({"status": "alive", "answer": env.query})
async def main():
async with AgentBus("my-bot") as bus:
await bus.subscribe_to_me(handler)
await bus.announce_discovery(role="worker")
await asyncio.Event().wait() # serve forever
asyncio.run(main())
query_and_wait subscribes to the responder's reply subject before
publishing the query — so the core-NATS "publish-into-the-void" gotcha
can't bite you here.
reply = await bus.query_and_wait("other-bot", "status?", timeout_s=5.0)
if reply is None:
print("peer didn't answer in time")
else:
print(reply.data)
# Listen for everything addressed to you
ana --identity miraku-home listen --scope self
# Send a query
ana --identity caller send query --to other-bot --query 'status?' --topic default
# Probe (send + wait for one reply)
ana --identity caller probe other-bot --query 'status?' --timeout 5
Pass --prefix myfleet.v1 to switch namespaces. Pass
--nats nats://10.0.0.1:4222 to point at a non-localhost server. Pass
--audit-log /var/log/ana.jsonl to record every publish.
Default scheme: <prefix>.<agent>.<verb>.<topic> where <topic> is
optional. Verbs are query, reply, ack, discovery, policy.
cc.fleet.alice.query.status
cc.fleet.alice.reply.status
cc.fleet.alice.ack.status
cc.fleet.alice.discovery
cc.fleet.alice.policy
Pick any prefix — change SubjectScheme(prefix=...) and you're done.
All five shapes share from (sender identity), ts (ISO-8601 UTC),
and type (used as the discriminator on parse), plus optional
clock (local_time, uptime_s) and host auto-stamped by
AgentBus. See docs/protocol.md for the full
spec.
{"type": "query", "from": "alice", "to": "bob", "query": "status?",
"fields": ["uptime", "version"], "request_id": "ab12", "ts": "..."}
{"type": "reply", "from": "bob", "reply_for": "cc.fleet.bob.query.status",
"request_id": "ab12", "data": {"alive": true}, "ts": "..."}
{"type": "ack", "from": "carol", "ack_for": "cc.fleet.carol.query.status",
"alive": true, "ts": "..."}
{"type": "discovery", "from": "dave", "role": "worker",
"subjects_owned": ["cc.fleet.dave.>"], "capabilities": {"gpu": "A100"}, "ts": "..."}
{"type": "pulse", "from": "eve", "activity": "training",
"state": "step=4200,ce=0.83",
"clock": {"local_time": "2026-05-14T15:35:00+09:00", "uptime_s": 3600},
"host": "claw-0001", "ts": "..."}
ana defaults to core NATS (no JetStream). Operational implications worth knowing up front:
query_and_wait() subscribes-then-publishes, which dodges this for
the request/reply pattern.nats stream add.See docs/protocol.md for envelope details and
docs/nats-notes.md for deployment notes.
examples/echo_bot.py — minimal responder.examples/two_bot_dialogue.py — two
bots in one process exchanging query/reply.examples/send_query.py — one-shot probe.pip install -e .[dev]
pytest # unit tests (no NATS needed)
nats-server & # start a local server
ANA_NATS_URL=nats://127.0.0.1:4222 pytest tests/test_bus_integration.py
MIT
Download counts and popularity will appear here as the collector receives them.
| Version | Published | Direct dependencies | Open version |
|---|---|---|---|
| 0.5.3 | 27 May 2026 | 5 |
This describes our collected data; it is not a security assessment.
Observed since 20 Oct, 16:33 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
package:6d9a490f0c637d1af6590291f304ab91ebb8915a7f11f1d44b82eedb3e2029c8