#[cfg(feature = "ui")]
use super::UiCommand;
use super::{
ArchiveAction, CaseCommand, ConfigAction, ContactCommand, DoctorAction, LogAction,
MessageAction, PurgeAction, PushAction, RemoteAction, RenderAction, SkillAction, TriageAction,
};
use clap::{Parser, Subcommand};
#[derive(Parser, Debug)]
#[command(name = "afmail", disable_version_flag = true, verbatim_doc_comment)]
#[doc = r#"Agent-First Mail: local-first email case workspace for agents.
### Interface Policy
- Files are the read interface; CLI is for effects.
- One workspace represents one mailbox account.
- Message commands use `afmail message ACTION MESSAGE_ID ...`.
- Case commands use `afmail case ACTION CASE_REF ...`.
- Active and archived cases are readable with `afmail case show REF` and
`afmail archive case show REF`.
- stdout carries structured Agent-First Data events; stderr is not a protocol channel.
### Workspace Shape
```text
.afmail/messages/ raw .eml plus durable remote sidecars
messages/ rebuildable parsed message cache
.afmail/logs/events.jsonl append-only audit log
.afmail/transactions/ transient local write transaction sentinels
.afmail/workspace.progress.json latest push/pull runtime snapshot
templates/ user-editable generated Markdown templates
triage/message_*.md active unprocessed message views
spam/*.md generated spam review views
trash/*.md generated trash review views
deleted/*.md generated remote-deleted review views
cases/<group>/<case_uid>-<name>/case.md generated case entry view
cases/<group>/<case_uid>-<name>/data/ canonical case state
cases/<group>/<case_uid>-<name>/views/ generated case detail views
contacts/<group>/<contact_uid>-<name>.md canonical contact cards
archive/contacts/<contact_uid>-<name>.md archived contact cards
archive/cases/<case_uid>-<name>/ archived case workspaces
archive/notifications/<archive_uid>-<name>/archive.md generated archive entry view
archive/notifications/<archive_uid>-<name>/data/ canonical archive state
archive/notifications/<archive_uid>-<name>/views/ generated archive detail views
```
### Examples
```text
afmail init
afmail init email-a
afmail skill status
afmail skill install --agent codex --scope workspace
afmail status
afmail doctor
afmail pull
afmail pull sent archive
afmail remote folders
afmail case create --name 应用反馈-肥料登记 --message message_inbox_607146690_21 --group open --reason "new feedback thread"
afmail case show c20260603001
afmail case add c20260603001 message_inbox_607146690_22 --reason "follow-up belongs to same feedback case"
afmail archive message create --name 服务通知 --message message_inbox_607146690_23 --summary "billing notification" --reason "billing notification"
afmail archive message show a20260603001
afmail archive message restore a20260603001 message_inbox_607146690_23 --reason "needs triage again"
afmail message spam message_inbox_607146690_23 --reason "phishing attempt"
afmail message trash message_inbox_607146690_24 --reason "duplicate no longer needed"
afmail render refresh
afmail doctor repair --confirm
afmail case move c20260603001 waiting
afmail case archive c20260603001 --reason "feedback handled"
afmail archive case restore c20260603001 --group open --reason "customer replied"
afmail case tag c20260603001 legal --reason "legal review needed"
afmail contact create --name "Zhang San" --email zhang@example.com --org Acme --role Buyer
afmail contact list --group people
afmail contact email add p20260603001 zhang-alt@example.com
afmail contact rename p20260603001 --name "Zhang Sanfeng"
afmail contact extract --from-triage
afmail contact archive p20260603001 --reason "left the company"
afmail case draft reply c20260603001 message_inbox_607146690_22
afmail case draft attach c20260603001 reply-message_inbox_607146690_22.md ./screenshot.png
afmail case draft change c20260603001 reply-message_inbox_607146690_22.md --body "Thanks, I will check this."
afmail case draft validate c20260603001 reply-message_inbox_607146690_22.md
afmail case draft send c20260603001 reply-message_inbox_607146690_22.md
afmail case draft remove c20260603001 reply-message_inbox_607146690_22.md --reason "mistaken draft"
afmail push list
afmail push
afmail push --confirm
afmail purge
afmail purge spam --older-than-days 30
afmail purge deleted
afmail log list --limit 20
afmail message show message_inbox_607146690_21
afmail message attachment fetch message_inbox_607146690_21 2
```
### Exit Codes
- `0`: command completed successfully
- `1`: runtime/store/protocol error
- `2`: invalid CLI arguments
"#]
pub struct Cli {
#[arg(long, default_value = "json", global = true)]
pub output: String,
#[arg(long, value_delimiter = ',', global = true)]
pub log: Vec<String>,
#[arg(long, global = true)]
pub verbose: bool,
#[arg(short = 'V', long, global = true)]
pub version: bool,
#[command(subcommand)]
pub command: Option<Command>,
}
#[derive(Subcommand, Debug)]
pub enum Command {
Init {
path: Option<String>,
},
Pull {
ids: Vec<String>,
},
Config {
#[command(subcommand)]
action: ConfigAction,
},
Remote {
#[command(subcommand)]
action: RemoteAction,
},
Push {
#[arg(long)]
dry_run: bool,
#[arg(long)]
confirm: bool,
#[command(subcommand)]
action: Option<PushAction>,
},
Status,
Doctor {
#[command(subcommand)]
action: Option<DoctorAction>,
},
Purge {
#[arg(long = "older-than-days", value_name = "DAYS")]
older_than_days: Option<u64>,
#[command(subcommand)]
action: Option<PurgeAction>,
},
Skill {
#[command(subcommand)]
action: SkillAction,
},
Triage {
#[command(subcommand)]
action: TriageAction,
},
Message {
#[command(subcommand)]
action: MessageAction,
},
Case {
#[command(subcommand)]
action: CaseCommand,
},
Contact {
#[command(subcommand)]
action: ContactCommand,
},
Archive {
#[command(subcommand)]
action: ArchiveAction,
},
Render {
#[command(subcommand)]
action: RenderAction,
},
Log {
#[command(subcommand)]
action: LogAction,
},
#[cfg(feature = "ui")]
Ui(UiCommand),
}