mirror of
https://github.com/beilunyang/moemail.git
synced 2026-09-05 23:36:37 +08:00
docs: add MoeMail CLI design spec for agent-first CLI tool
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,239 @@
|
|||||||
|
# MoeMail CLI — Agent-First Command Line Tool
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
A CLI tool that wraps MoeMail's existing OpenAPI, optimized for AI Agent workflows. Agents can create temporary emails, wait for incoming messages, read content, and manage mailboxes through simple shell commands.
|
||||||
|
|
||||||
|
**Goal:** Make MoeMail a first-class tool in any AI Agent's toolchain with minimal friction — one command per action, structured JSON output, zero server-side changes.
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
```
|
||||||
|
Agent (Claude / GPT / Custom)
|
||||||
|
↓ shell call
|
||||||
|
moemail CLI (npm package, bun-built single JS file)
|
||||||
|
↓ HTTPS + X-API-Key header
|
||||||
|
MoeMail Server (existing Next.js API, no changes)
|
||||||
|
↓
|
||||||
|
Cloudflare D1 / Email Workers
|
||||||
|
```
|
||||||
|
|
||||||
|
- **Language:** TypeScript
|
||||||
|
- **Build:** `bun build ./src/index.ts --outdir ./dist --target=node`
|
||||||
|
- **Distribution:** npm package, `npm i -g moemail-cli`
|
||||||
|
- **Binary:** `package.json` `bin` field points to `dist/index.js`
|
||||||
|
- **Location:** `packages/moemail-cli/` in the monorepo
|
||||||
|
- **Server changes:** None. CLI is a pure API client.
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
Stored at `~/.moemail/config.json`:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"apiUrl": "https://moemail.app",
|
||||||
|
"apiKey": "mk_xxxxxxxx"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Environment variable overrides (higher priority):
|
||||||
|
- `MOEMAIL_API_URL`
|
||||||
|
- `MOEMAIL_API_KEY`
|
||||||
|
|
||||||
|
## Commands
|
||||||
|
|
||||||
|
All commands support `--json` for JSON output and `--help` for usage info.
|
||||||
|
|
||||||
|
### `moemail config`
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Interactive setup
|
||||||
|
moemail config
|
||||||
|
|
||||||
|
# Direct set
|
||||||
|
moemail config set api-url https://moemail.app
|
||||||
|
moemail config set api-key mk_xxxxxxxx
|
||||||
|
|
||||||
|
# View current config
|
||||||
|
moemail config list
|
||||||
|
```
|
||||||
|
|
||||||
|
### `moemail create`
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Random prefix, 1h expiry (defaults)
|
||||||
|
moemail create
|
||||||
|
|
||||||
|
# With parameters
|
||||||
|
moemail create --name test --domain moemail.app --expiry 24h
|
||||||
|
```
|
||||||
|
|
||||||
|
`--expiry` options: `1h` | `24h` | `3d` | `7d` | `permanent`
|
||||||
|
|
||||||
|
Default output:
|
||||||
|
```
|
||||||
|
Created: test@moemail.app (expires in 24 hours)
|
||||||
|
ID: abc-123
|
||||||
|
```
|
||||||
|
|
||||||
|
JSON output (`--json`):
|
||||||
|
```json
|
||||||
|
{"id": "abc-123", "address": "test@moemail.app", "expiresAt": "2026-03-23T12:00:00Z"}
|
||||||
|
```
|
||||||
|
|
||||||
|
### `moemail list`
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# List all mailboxes
|
||||||
|
moemail list
|
||||||
|
|
||||||
|
# With pagination
|
||||||
|
moemail list --cursor xxx
|
||||||
|
```
|
||||||
|
|
||||||
|
### `moemail wait`
|
||||||
|
|
||||||
|
The core command for Agent workflows. Polls the API until a new message arrives or timeout.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Wait for new message (default: 120s timeout, 5s interval)
|
||||||
|
moemail wait --email-id xxx
|
||||||
|
|
||||||
|
# Custom timeout and interval
|
||||||
|
moemail wait --email-id xxx --timeout 60 --interval 3
|
||||||
|
```
|
||||||
|
|
||||||
|
**Behavior:**
|
||||||
|
1. Record current message count/IDs on start
|
||||||
|
2. Poll `GET /api/emails/{id}` every `--interval` seconds
|
||||||
|
3. Compare with initial state to detect new messages
|
||||||
|
4. On new message: output message summary and exit with code 0
|
||||||
|
5. On timeout: exit with code 1
|
||||||
|
|
||||||
|
Default output:
|
||||||
|
```
|
||||||
|
Polling... (15/120s)
|
||||||
|
New message from no-reply@github.com: "Verify your email"
|
||||||
|
Message ID: msg-456
|
||||||
|
```
|
||||||
|
|
||||||
|
JSON output (`--json`):
|
||||||
|
```json
|
||||||
|
{"messageId": "msg-456", "from": "no-reply@github.com", "subject": "Verify your email", "receivedAt": "2026-03-22T12:05:00Z"}
|
||||||
|
```
|
||||||
|
|
||||||
|
### `moemail read`
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Read message (default: plain text)
|
||||||
|
moemail read --email-id xxx --message-id yyy
|
||||||
|
|
||||||
|
# HTML format
|
||||||
|
moemail read --email-id xxx --message-id yyy --format html
|
||||||
|
```
|
||||||
|
|
||||||
|
`--format` options: `text` (default) | `html`
|
||||||
|
|
||||||
|
### `moemail send`
|
||||||
|
|
||||||
|
```bash
|
||||||
|
moemail send --email-id xxx --to user@example.com --subject "Hello" --content "Body text"
|
||||||
|
```
|
||||||
|
|
||||||
|
### `moemail delete`
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Delete mailbox and all messages
|
||||||
|
moemail delete --email-id xxx
|
||||||
|
|
||||||
|
# Delete single message
|
||||||
|
moemail delete --email-id xxx --message-id yyy
|
||||||
|
```
|
||||||
|
|
||||||
|
## Output Specification
|
||||||
|
|
||||||
|
### Modes
|
||||||
|
|
||||||
|
| Mode | Flag | Format | Use case |
|
||||||
|
|------|------|--------|----------|
|
||||||
|
| Text | (default) | Human-readable | Debugging, manual use |
|
||||||
|
| JSON | `--json` | Single-line JSON on stdout | Agent consumption |
|
||||||
|
|
||||||
|
### Exit Codes
|
||||||
|
|
||||||
|
| Code | Meaning |
|
||||||
|
|------|---------|
|
||||||
|
| 0 | Success |
|
||||||
|
| 1 | Operation failed (timeout, not found, bad params) |
|
||||||
|
| 2 | Auth failed (invalid/expired API Key) |
|
||||||
|
|
||||||
|
### Error Handling
|
||||||
|
|
||||||
|
- Errors write to **stderr**, never stdout
|
||||||
|
- In `--json` mode, stdout contains only valid JSON (or nothing on failure)
|
||||||
|
- Agent reads stdout for data, checks exit code for success/failure
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ moemail wait --email-id xxx --timeout 10 --json
|
||||||
|
# stderr: Polling... (3/10s)
|
||||||
|
# stderr: Timeout: no new messages received
|
||||||
|
# stdout: (empty)
|
||||||
|
# exit code: 1
|
||||||
|
```
|
||||||
|
|
||||||
|
## Project Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
packages/moemail-cli/
|
||||||
|
├── src/
|
||||||
|
│ ├── index.ts # Entry point, command registration
|
||||||
|
│ ├── commands/
|
||||||
|
│ │ ├── config.ts # config command
|
||||||
|
│ │ ├── create.ts # create command
|
||||||
|
│ │ ├── list.ts # list command
|
||||||
|
│ │ ├── wait.ts # wait command (client-side polling)
|
||||||
|
│ │ ├── read.ts # read command
|
||||||
|
│ │ ├── send.ts # send command
|
||||||
|
│ │ └── delete.ts # delete command
|
||||||
|
│ ├── api.ts # HTTP client wrapping all API calls
|
||||||
|
│ ├── config.ts # Read/write ~/.moemail/config.json
|
||||||
|
│ └── output.ts # Output formatting (text / json)
|
||||||
|
├── package.json
|
||||||
|
├── tsconfig.json
|
||||||
|
└── README.md
|
||||||
|
```
|
||||||
|
|
||||||
|
## Dependencies
|
||||||
|
|
||||||
|
- **commander** — CLI argument parsing and subcommand routing
|
||||||
|
- All other needs (HTTP, filesystem) use Node.js built-in APIs
|
||||||
|
|
||||||
|
## Relationship to Main Project
|
||||||
|
|
||||||
|
- Lives in `packages/moemail-cli/`, published as a separate npm package
|
||||||
|
- No code shared with the main Next.js app
|
||||||
|
- Only coupling is the API contract (URLs, request/response shapes)
|
||||||
|
- Server-side: zero changes required
|
||||||
|
|
||||||
|
## Typical Agent Workflow
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. Create a temporary mailbox
|
||||||
|
EMAIL=$(moemail create --domain moemail.app --expiry 1h --json)
|
||||||
|
EMAIL_ID=$(echo $EMAIL | jq -r '.id')
|
||||||
|
ADDRESS=$(echo $EMAIL | jq -r '.address')
|
||||||
|
|
||||||
|
# 2. Use the address to sign up for a service (agent does this elsewhere)
|
||||||
|
|
||||||
|
# 3. Wait for verification email
|
||||||
|
MSG=$(moemail wait --email-id $EMAIL_ID --timeout 120 --json)
|
||||||
|
MSG_ID=$(echo $MSG | jq -r '.messageId')
|
||||||
|
|
||||||
|
# 4. Read the email content
|
||||||
|
CONTENT=$(moemail read --email-id $EMAIL_ID --message-id $MSG_ID --json)
|
||||||
|
|
||||||
|
# 5. Agent extracts verification code from content (LLM does this)
|
||||||
|
|
||||||
|
# 6. Clean up
|
||||||
|
moemail delete --email-id $EMAIL_ID
|
||||||
|
```
|
||||||
Reference in New Issue
Block a user