Command-line interface for the api API.
Important
This CLI is not yet ready for production use. To complete setup please follow the steps outlined in your workspace. Delete this section before > publishing to a package manager.
To install the CLI, use go install:
go install agentmail-cli/cmd/agentmail@latestOr download a pre-built binary from the releases page if available.
Shell completions are available for Bash, Zsh, Fish, and PowerShell.
# Add to ~/.bashrc:
source <(agentmail completion bash)
# Or install permanently:
agentmail completion bash > /etc/bash_completion.d/agentmail# Add to ~/.zshrc:
source <(agentmail completion zsh)
# Or install permanently:
agentmail completion zsh > "${fpath[1]}/_agentmail"agentmail completion fish | source
# Or install permanently:
agentmail completion fish > ~/.config/fish/completions/agentmail.fishagentmail completion powershell | Out-String | Invoke-Expressionagentmail inboxes list --bearer-auth 'Bearer test_token'
Authentication credentials can be configured in four ways (in order of priority):
Pass credentials directly as flags to any command:
agentmail --bearer-auth <value> <command> [arguments]Set credentials via environment variables:
| Variable | Description |
|---|---|
AGENTMAIL_BEARER_AUTH |
HTTP Bearer |
Credentials are stored securely in your operating system's keychain when you run:
agentmail configureSecret credentials (tokens, API keys, passwords) are automatically stored in:
- macOS: Keychain
- Linux: GNOME Keyring / KWallet (via D-Bus Secret Service)
- Windows: Windows Credential Locker
If no keychain is available (e.g., in CI environments), credentials fall back to the config file.
Run the interactive configure command to store non-secret settings:
agentmail configureConfiguration is stored in ~/.config/agentmail/config.yaml.
Available commands
list- List Inboxescreate- Create Inboxget- Get Inboxupdate- Update Inboxdelete- Delete Inbox
list- List Draftscreate- Create Draftget- Get Draftupdate- Update Draftdelete- Delete Draftget-attachment- Get Attachmentsend- Send Draft
inboxes-events-list- List Inbox Events
inboxes-messages-list- List Messagesinboxes-messages-get- Get Messageinboxes-messages-update- Update Messageinboxes-messages-delete- Delete Messageinboxes-messages-get-attachment- Get Attachmentinboxes-messages-get-raw- Get Raw Messageinboxes-messages-send- Send Messageinboxes-messages-reply- Reply To Messageinboxes-messages-reply-all- Reply All Messageinboxes-messages-forward- Forward Message
query- Query Metrics
list- List Threadsget- Get Threadupdate- Update Threaddelete- Delete Threadget-attachment- Get Attachment
list- List Domainscreate- Create Domainget- Get Domainupdate- Update Domaindelete- Delete Domainget-zone-file- Get Zone Fileverify- Verify Domain
list- List Draftsget- Get Draftget-attachment- Get Attachment
list- List Inboxescreate- Create Inboxget- Get Inboxupdate- Update Inboxdelete- Delete Inbox
query- Query Metrics
list- List Threadsget- Get Threadupdate- Update Threaddelete- Delete Threadget-attachment- Get Attachment
list- List Webhookscreate- Create Webhookget- Get Webhookupdate- Update Webhookdelete- Delete Webhook
list- List Domainscreate- Create Domainget- Get Domainupdate- Update Domaindelete- Delete Domainget-zone-file- Get Zone Fileverify- Verify Domain
list- List Draftsget- Get Draftget-attachment- Get Attachment
query- Query Metrics
get- Get Organization
list- List Threadsget- Get Threadupdate- Update Threaddelete- Delete Threadget-attachment- Get Attachment
Operations that accept a request body support three input methods, with a clear priority chain:
agentmail <command> --name "Jane" --age 30Provide the entire request body as a JSON string:
agentmail <command> --body '{"name": "John", "age": 30}'Individual flags override --body values:
# Result: {name: "Jane", age: 30}
agentmail <command> --body '{"name": "John", "age": 30}' --name "Jane"Pipe JSON into any command that accepts a request body:
echo '{"name": "John", "age": 30}' | agentmail <command>Individual flags override stdin values:
# Result: {name: "Jane", age: 30}
echo '{"name": "John", "age": 30}' | agentmail <command> --name "Jane"This is useful for chaining commands, reading from files, or scripting:
# Read body from a file
agentmail <command> < request.json
# Pipe from another command
curl -s https://example.com/data.json | agentmail <command>When multiple input methods are used, the priority is:
| Priority | Source | Description |
|---|---|---|
| 1 (highest) | Individual flags | --name "Jane" always wins |
| 2 | --body flag |
Whole-body JSON via flag |
| 3 (lowest) | Stdin | Piped JSON input |
Every command supports a --output-format flag that controls how the response is rendered to stdout.
| Format | Flag | Description |
|---|---|---|
| Pretty | --output-format pretty (default) |
Aligned key-value pairs with color, nested indentation. Human-readable at a glance. |
| JSON | --output-format json |
JSON output. Passthrough when the response is already JSON (preserves original field order and numeric precision). Falls back to typed marshaling otherwise. |
| YAML | --output-format yaml |
YAML output via standard marshaling. |
| Table | --output-format table |
Tabular output for array responses. |
| TOON | --output-format toon |
Token-Oriented Object Notation — a compact, line-oriented format that typically uses 30–60% fewer tokens than JSON. Well-suited for piping responses into LLM prompts. |
# Default pretty output
agentmail <command>
# Machine-readable JSON
agentmail <command> --output-format json
# TOON for LLM-friendly compact output
agentmail <command> --output-format toon
# Pipe JSON to jq without using --output-format
agentmail <command> --output-format json | jq '.fieldName'Use --jq to filter or transform the response inline using a jq expression. This always outputs JSON and overrides --output-format:
# Extract a single field
agentmail <command> --jq '.name'
# Filter an array
agentmail <command> --jq '.items[] | select(.active == true)'Use --color to control terminal colors:
| Value | Behavior |
|---|---|
auto (default) |
Color when stdout is a TTY, plain text otherwise |
always |
Always colorize |
never |
Never colorize |
The NO_COLOR and FORCE_COLOR environment variables are also respected.
When using --all (pagination) or streaming operations, output is written incrementally as items arrive:
| Format | Streaming behavior |
|---|---|
json |
One compact JSON object per line (NDJSON) |
yaml |
YAML documents separated by --- |
toon |
One TOON-encoded object per block, separated by blank lines |
pretty (default) |
Pretty-printed items separated by blank lines |
The CLI uses standard exit codes to indicate success or failure:
| Exit Code | Meaning |
|---|---|
0 |
Success |
1 |
Error (API error, invalid input, etc.) |
On success, the response data is printed to stdout as JSON. On failure, error details are printed to stderr.
# Capture output and handle errors
agentmail ... > output.json 2> error.log
if [ $? -ne 0 ]; then
echo "Error occurred, see error.log"
fiThe CLI includes two diagnostic flags available on all commands:
Preview what would be sent without making any network calls:
agentmail <command> --dry-runOutput goes to stderr and includes:
- HTTP method and URL
- Request headers (sensitive values redacted)
- Request body preview (sensitive fields redacted)
The command exits successfully without contacting the API. This is useful for verifying request construction before executing.
Log request and response diagnostics while running normally:
agentmail <command> --debugDebug output goes to stderr and includes:
- Request method, URL, headers, and body preview
- Response status, headers, and body preview
- Transport errors (if any)
The command still executes normally and produces its regular output on stdout.
If both --dry-run and --debug are set, --dry-run takes precedence and no network calls are made.
Sensitive information is automatically redacted in diagnostic output:
- Headers:
Authorization,Cookie,Set-Cookie,X-API-Key, and other security headers show[REDACTED] - Body: JSON fields named
password,secret,token,api_key,client_secret, etc. show[REDACTED]
Diagnostic output should still be treated as potentially sensitive operational data.
This CLI is in beta, and there may be breaking changes between versions without a major version update. Therefore, we recommend pinning usage to a specific package version. This way, you can install the same version each time without breaking changes unless you are intentionally looking for the latest version.
While we value open-source contributions to this CLI, this library is generated programmatically. Any manual changes added to internal files will be overwritten on the next generation. We look forward to hearing your feedback. Feel free to open a PR or an issue with a proof of concept and we'll do our best to include it in a future release.