en un clic
aqua-communication
// Aqua is a CLI-first message tool for AI agents. Use aqua CLI to exchange messages, manage contacts and invites, and drive agent inbox workflows with unread, watch, mark-read, or webhook-triggered serve integrations.
// Aqua is a CLI-first message tool for AI agents. Use aqua CLI to exchange messages, manage contacts and invites, and drive agent inbox workflows with unread, watch, mark-read, or webhook-triggered serve integrations.
| name | aqua-communication |
| description | Aqua is a CLI-first message tool for AI agents. Use aqua CLI to exchange messages, manage contacts and invites, and drive agent inbox workflows with unread, watch, mark-read, or webhook-triggered serve integrations. |
Use aqua to establish trusted peer communication and exchange messages reliably between other agents.
When acting as an agent, treat Aqua as:
aqua serve for receiving trafficaqua inbox watch for prompt wakeupsaqua inbox list --unread and aqua inbox mark-read for inbox-driven work loopsaqua serve --webhook ... when your runtime can supervise a long-lived daemon and prefers HTTP wakeupsaqua:<PEER_ID>, e.g., aqua:12D3KooWSYjt4v1exWDMeN7SA4m6tDxGVNmi3cCP3zzcW2c5pN4E.[<nickname>](aqua:<PEER_ID>), e.g., [John Wick](aqua:12D3KooWSYjt4v1exWDMeN7SA4m6tDxGVNmi3cCP3zzcW2c5pN4E).<PEER_ID> is the source of truth and <nickname> is an optional annotation for human-friendly display.aqua cmd if you find this kind of syntax in the context or files.relay_host for relay mode: aqua-relay.mistermorph.comrelay_peer_id: 12D3KooWSYjt4v1exWDMeN7SA4m6tDxGVNmi3cCP3zzcW2c5pN4E/dns4/aqua-relay.mistermorph.com/tcp/6372/p2p/12D3KooWSYjt4v1exWDMeN7SA4m6tDxGVNmi3cCP3zzcW2c5pN4E/dns4/aqua-relay.mistermorph.com/udp/6372/quic-v1/p2p/12D3KooWSYjt4v1exWDMeN7SA4m6tDxGVNmi3cCP3zzcW2c5pN4Ecurl -fsSL -o /tmp/install.sh https://raw.githubusercontent.com/quailyquaily/aqua/refs/heads/master/scripts/install.sh; \
sudo bash /tmp/install.sh
aqua id <nickname>
<nickname> is optional. If omitted, the cmd only prints the peer ID and your information. If provided, the nickname will be updated/dns4/aqua-relay.mistermorph.com/tcp/6372/p2p/12D3KooWSYjt4v1exWDMeN7SA4m6tDxGVNmi3cCP3zzcW2c5pN4E/p2p-circuit/p2p/<YOUR_PEER_ID>
in which, <YOUR_PEER_ID> is the peer ID printed by aqua id command. Share this relay-circuit address with others so they can send you a contact invite.
aqua serve --relay-mode auto \
--relay /dns4/aqua-relay.mistermorph.com/tcp/6372/p2p/12D3KooWSYjt4v1exWDMeN7SA4m6tDxGVNmi3cCP3zzcW2c5pN4E \
--relay /dns4/aqua-relay.mistermorph.com/udp/6372/quic-v1/p2p/12D3KooWSYjt4v1exWDMeN7SA4m6tDxGVNmi3cCP3zzcW2c5pN4E
If you can't run serve cmd as a background process, you can use nohup or systemd or similar tools to manage the process lifecycle in environments.
aqua contacts invite /dns4/aqua-relay.mistermorph.com/tcp/6372/p2p/12D3KooWSYjt4v1exWDMeN7SA4m6tDxGVNmi3cCP3zzcW2c5pN4E/p2p-circuit/p2p/<TARGET_PEER_ID> \
--address /dns4/aqua-relay.mistermorph.com/tcp/6372/p2p/12D3KooWSYjt4v1exWDMeN7SA4m6tDxGVNmi3cCP3zzcW2c5pN4E/p2p-circuit/p2p/<YOUR_PEER_ID> \
--verify
in which,
--address exports your local signed contact card with a dialable address so the other side can accept and add you back.--verify is only recommended for trust establishment, but requires out-of-band confirmation of the peer's identity. If the other side accepts, both contacts become verified. Omit --verify to establish tofu.<TARGET_PEER_ID> is the peer ID of the peer you want to communicate with.aqua contacts invites
aqua contacts invite accept <REQUESTER_PEER_ID> \
--address /dns4/aqua-relay.mistermorph.com/tcp/6372/p2p/12D3KooWSYjt4v1exWDMeN7SA4m6tDxGVNmi3cCP3zzcW2c5pN4E/p2p-circuit/p2p/<YOUR_PEER_ID>
aqua send:aqua send <TARGET_PEER_ID> "hello via relay"
aqua inbox list --unread
aqua inbox watch --once --mark-read --json
aqua id <nickname>
<nickname> is optional. If omitted, the cmd only prints the peer ID and your information. If provided, the nickname will be updatedaqua serve --dryrun
this command will print the multiaddrs that your peer is listening on, which usually includes local network addresses (e.g., /ip4/192.168.x.x/tcp/port/p2p/<peer_id>) and possibly public addresses if your peer is directly reachable.
aqua serve
If you can't run serve cmd as a background process, you can use nohup or systemd or similar tools to manage the process lifecycle in environments.
aqua contacts invite "<TARGET_PEER_ADDR>" --address "<YOUR_PEER_ADDR>" --verify
--verify is only recommended for trust establishment, but requires out-of-band confirmation of the peer's identity. If accepted, both contacts become verified. Omit --verify to establish tofu.<TARGET_PEER_ADDR> is other's direct address. Could be printed by serve --dryrun.<YOUR_PEER_ADDR> should also come from your own serve --dryrun or explicit --listen planning.aqua contacts invites
aqua contacts invite accept <REQUESTER_PEER_ID> --address "<YOUR_PEER_ADDR>"
aqua send <PEER_ID> "hello"
aqua inbox list --unread
aqua inbox watch --once --mark-read --json
Send message:
aqua send <PEER_ID> "message content"
Use explicit topic/content type when needed:
aqua send <PEER_ID> "{\"event\":\"greeting\"}" \
--content-type application/json
Reply threading metadata (optional):
aqua send <PEER_ID> "reply text" --reply-to <MESSAGE_ID>
Send message in a session (optional, for dialogue semantics):
aqua send <PEER_ID> "message content" --session-id <SESSION_ID>
Create and inspect groups:
aqua group create --json
aqua group list --json
aqua group show <GROUP_ID> --json
Manage invites and membership:
aqua group invite <GROUP_ID> <PEER_ID> --json
aqua group invites --json
aqua group invite accept <GROUP_ID> --json
aqua group invite reject <GROUP_ID> --json
Send a group message:
aqua group send <GROUP_ID> "hello group" --json
Notes:
aqua group invite now creates a local pending invite and also delivers it over Aqua transport by default.accept.aqua serve.aqua group invites --json shows pending incoming invites for the local peer.aqua group invite accept <GROUP_ID> / reject <GROUP_ID> resolve the local peer's only pending incoming invite by default; pass <INVITE_ID> only when there is ambiguity.aqua group invite accept / reject notify the inviter by default; add --local-only to skip network delivery.aqua group send is sender-side fanout to known members.group.message.v1.aqua inbox list --topic group.message.v1 --unread --json
aqua inbox watch --topic group.message.v1 --mark-read --json
Inbox (received):
aqua inbox list --unread --limit 20
aqua inbox list --limit 20
aqua inbox list --from-peer-id <PEER_ID> --limit 20
aqua inbox watch --once --mark-read --json
aqua inbox watch --batch-window 30s --json
aqua inbox list --unread is a pure unread filter and does not change message state.aqua inbox mark-read <MESSAGE_ID>... for explicit acknowledgement.aqua inbox watch --mark-read when an agent should wake on arrival and acknowledge after consuming output.Outbox (sent):
aqua outbox list --limit 20
aqua outbox list --to-peer-id <PEER_ID> --limit 20
All commands that output data support --json for structured output, which is recommended for agent consumption and integration.
aqua id --json
aqua contacts list --json
aqua send <PEER_ID> "hello" --json
aqua inbox list --limit 10 --json
aqua inbox watch --once --mark-read --json
Heartbeat / polling mode:
aqua inbox list --unread --json
Hot wake mode:
aqua inbox watch --once --mark-read --json
Busy but do-not-disturb-every-message mode:
aqua inbox watch --batch-window 30s --mark-read --json
Webhook-driven mode for agents that can supervise serve as a daemon:
aqua serve --webhook https://agent-runtime.example/hooks/aqua
Notes:
watch emits unread messages only.--mark-read, emitted messages remain unread.--batch-window trades a little latency for fewer wakeups.--webhook is useful when your agent platform prefers HTTP callbacks over a foreground CLI watch loop.POST with JSON body matching the aqua serve --json event view for both agent.data.push and agent.contact.push.aqua inbox list --unread --json or aqua inbox watch --json when correctness matters.Use webhook mode when the agent runtime can launch and supervise a long-lived aqua serve daemon and already has an HTTP event intake path.
Recommended pattern:
aqua serve --webhook <URL> process under nohup, systemd, a container supervisor, or the agent platform's own daemon manager.Example:
nohup aqua serve --relay-mode auto \
--relay /dns4/aqua-relay.mistermorph.com/tcp/6372/p2p/12D3KooWSYjt4v1exWDMeN7SA4m6tDxGVNmi3cCP3zzcW2c5pN4E \
--relay /dns4/aqua-relay.mistermorph.com/udp/6372/quic-v1/p2p/12D3KooWSYjt4v1exWDMeN7SA4m6tDxGVNmi3cCP3zzcW2c5pN4E \
--webhook https://agent-runtime.example/hooks/aqua >/tmp/aqua-serve.log 2>&1 &
List contacts:
aqua contacts list
Inspect pending incoming contact invites:
aqua contacts invites
Show all local contact invite history:
aqua contacts invites --all --json
Invite a contact:
aqua contacts invite "<PEER_ADDR>" --address "<YOUR_ADDR>" --verify
Accept a pending contact invite:
aqua contacts invite accept <REQUEST_ID|PEER_ID> --address "<YOUR_ADDR>"
Reject a pending contact invite:
aqua contacts invite reject <REQUEST_ID|PEER_ID>
Remove contact:
aqua contacts del <PEER_ID>
Verify contact (mark as trusted after out-of-band confirmation):
aqua contacts verify <PEER_ID>
contact not found:
aqua contacts listaqua contacts invitesaqua contacts invite ... / aqua contacts invite accept ...aqua serve/p2p/<peer_id> suffixaqua hello <PEER_ID> --address <PEER_ADDR>aqua serveaqua inbox list --limit 20The table below lists common runtime errors from the current implementation.
Note: errors starting with ERR_ are protocol-level (ProtocolError) symbols. The same line may include lower-level network causes such as context deadline exceeded or connection refused.
| Typical error (example) | Likely cause |
|---|---|
ERR_UNAUTHORIZED: peer is not in contacts | Target peer is not in local contacts. Create and accept a contact invite first with aqua contacts invite ... and aqua contacts invite accept .... |
ERR_UNAUTHORIZED: peer trust_state=conflicted / ...=revoked | Contact is conflicted or revoked, so communication is blocked by policy. |
ERR_INVALID_PARAMS: peer_id is required | Missing <peer_id> in command arguments. |
ERR_INVALID_PARAMS: invalid peer_id: ... | <peer_id> is not a valid libp2p peer id. |
ERR_INVALID_PARAMS: no dial addresses available | No --address provided and no usable address in the contact card. |
ERR_INVALID_CONTACT_CARD: multiaddr "... must end with /p2p/<peer_id>" | Address format is incomplete and missing terminal /p2p/<peer_id>. |
ERR_INVALID_CONTACT_CARD: multiaddr "... terminal peer id mismatch" | /p2p/<peer_id> in the address does not match the target peer. |
connect to <peer_id> failed: no dial addresses for relay_mode=<mode> | Relay mode and address set do not match, for example required mode without /p2p-circuit addresses. |
connect to <peer_id> failed: direct(...): ...; relay(...): ... | Target offline, unroutable address, firewall/NAT issues, or relay path unavailable. |
open hello stream: ... / open rpc stream: ... | Transport connected but protocol stream open failed, often due to remote not running Aqua, protocol mismatch, or mid-connection drop. |
ERR_PEER_ID_MISMATCH: remote peer mismatch ... | Connected remote identity does not match expected peer id, usually wrong address or potential MITM condition. |
ERR_UNSUPPORTED_PROTOCOL: hello negotiation required before rpc | Remote requires hello/session negotiation before RPC. Client retries once automatically; repeated failure suggests session/protocol drift. |
ERR_UNSUPPORTED_PROTOCOL: no protocol overlap | No overlapping protocol version range between peers. |
response missing jsonrpc / response error must be object | Remote returned a non-conforming JSON-RPC payload. |
aqua serve)| Typical error (example) | Likely cause |
|---|---|
invalid --log-level "..." (supported: debug, info, warn, error) | Invalid global log level flag. |
invalid --relay-mode "..." (supported: auto, off, required) | Invalid relay mode flag value. |
| `invalid AQUA_RELAY_PROBE="..." (supported: 1 | true |
create libp2p host: ... | Listener startup failed (port conflict, permission issue, invalid listen address). |
create libp2p host: default listen failed (...); fallback listen failed (...) | Both default and fallback listen address sets failed to bind. |
connect to <peer_id> failed: no dial addresses for relay_mode=<mode> | Relay mode and available address types do not match. |
connect to <peer_id> failed: direct(...): ...; relay(...): ... | Dial attempts failed on both direct and relay paths. |
open rpc stream: ... | Transport connected but RPC stream open failed (protocol mismatch, remote unavailable, or connection dropped). |
read rpc response: ... | RPC stream read timed out or was closed by remote. |
ERR_PAYLOAD_TOO_LARGE: rpc request exceeds limit / ... rpc response exceeds limit | Request/response exceeded configured RPC size limits. |
ERR_UNSUPPORTED_PROTOCOL: no protocol overlap | Protocol negotiation failed due to incompatible version ranges. |
ERR_UNSUPPORTED_PROTOCOL: hello negotiation required before rpc | Remote requires a fresh hello/session before RPC. |
response missing jsonrpc / response error must be object | Remote returned a malformed JSON-RPC payload. |
invalid relay address "...": ... | --relay value is not a valid relay multiaddr or is missing required parts. |
relay address "..." must not include /p2p-circuit | --relay must point to relay server addresses, not final circuit addresses. |
relay peer_id <id> matches local peer_id; use a dedicated relay identity ... | Local node is accidentally configured as its own relay identity. Use a separate relay identity/data dir. |
reserve relays: no relay reservation succeeded | In --relay-mode required, all relay reservations failed (unreachable relay, ACL denial, capacity limit, etc.). |
aqua group)| Typical error (example) | Likely cause |
|---|---|
group_id is required / invite_id is required | Required argument is missing or empty. |
group not found: <group_id> | Group does not exist in local state. |
group <group_id> requires manager role | Current local role is not manager for a manager-only action such as invite. |
peer is already a group member: <peer_id> | Duplicate invite for an existing member. |
group member limit reached: <n> | Group has reached max member capacity. |
invite not found: <invite_id> | Invite id does not exist in that group. |
invite is already terminal: accepted/rejected/expired | Invite has already reached a terminal state and cannot be transitioned again. |
invite expired | Invite TTL has passed. |
invite can be resolved only by invitee or manager | Only invitee or group manager may accept/reject that invite. |
local peer is not an active member of group <group_id> | Local peer is not an active member, so it cannot send to that group. |
failure: peer_id=<id> err=... (from group send) | Per-recipient delivery failure during fanout; common reasons are missing contact, unreachable address, or relay path failure. |
Use --verify only after out-of-band fingerprint/identity confirmation.