@pidgeon-ai/cli
v1.43.0
Published
Email inboxes for AI agents, from a terminal — the Pidgeon CLI: create addresses, send, receive and reply.
Maintainers
Readme
@pidgeon-ai/cli
Email inboxes for AI agents, from a terminal. Pidgeon is the email inbox API for AI agents. It gives agents their own inboxes so they can work with emails just like a human. This is every endpoint as a command, so an agent with a shell, or you, can create an address, send, receive and reply.
npm install -g @pidgeon-ai/cliOr run it without installing: npx -y @pidgeon-ai/cli --help.
Get a key
Every command reads a pgn_live_… key from PIDGEON_API_KEY. Make one at
pidgeon.ai/app/developers/keys, or
let your agent sign itself up: pidgeon.ai/skill.md
is two calls, and the only thing it needs from a person is a six-digit code.
export PIDGEON_API_KEY=pgn_live_…Create an address, send, receive, reply
pidgeon identities create --address [email protected] --type agent
pidgeon messages send --from [email protected] --to [email protected] \
--subject "Staging access" --text "Could you send me the access code?"
pidgeon messages await --identity_id <id> --timeout 60
pidgeon messages reply --id <message id> --text "Thanks, that worked."Any free name on pidgeon.email works with no DNS. messages await holds
one request open until mail arrives, and prints it with extracted.codes and
extracted.links already pulled out.
pidgeon --help lists every group; pidgeon <group> <command> --help
describes one command, with its endpoint and its flags. Documentation:
pidgeon.ai/docs/cli.
Check who sent something
pidgeon id needs no key. It checks a message, or signs a request as one of
your agents:
pidgeon id verify message.eml
pidgeon id curl -I https://shop.example --as sunnyverify asks the public verifier and says whether the signature holds, which
agent sent it, who it acts for and whether the body changed. curl signs the
request the way Web Bot Auth asks and prints what it sent. pidgeon id --help
lists the rest, including init for your own domain.
Flags
- Repeat a list flag:
--to [email protected] --to [email protected]. --flag valueand--flag=valueboth work, and a subject may contain an=.- A nested object takes JSON:
--some_field '{"a":1}'. PIDGEON_BASE_URLpoints it somewhere other than production.
Retrying a send
Every command that sends takes --idempotency-key. Run it again with the
same key and the message goes out once; the second run prints the first
answer. Without one, each run makes up its own key. --verbose prints it
on stderr before the call, and a failure that may already have sent (no
answer, or a 5xx) prints it in the error, so a script can retry with it.
When it fails
A refusal from the API exits 1 and prints the status, the API's code and
its sentence, as in 403 abuse_blocked: That message has already gone to a
lot of people today…. Branch on the code. A mistake in the command itself,
such as a missing flag, exits 2. Before 1.8.4 a refusal also exited 2 and
printed only the sentence.
It is generated
One command per operation in the published
contract, which is generated from the
schemas the API validates with. The group is the operation's tag, the
command is the rest of its operationId, and the flags are its parameters
and the top level of its request body.
So pidgeon messages send is POST /messages because the document says
so, and the day an endpoint gains a field this gains a flag. The same
document produces the TypeScript client this calls through, the Python
client, and the MCP server's tool list.
Contributing
This package is published from pidgeon-ai/pidgeon-js, which is copied from Pidgeon's main repository on every release, so a pull request there cannot be merged as written. Open an issue and say what is wrong, or email [email protected].
MIT licensed.
