Use this skill when an autonomous or semi-autonomous agent must operate eppie-console directly.
eppie-console is a console mail client that can work with:
Use eppie-console in a predictable, automation-friendly way to:
This skill focuses on deterministic command execution, structured output handling, and explicit standard-input contracts.
For end-to-end validation, coverage, and reproducible test scenarios, use eppie-cli-agent-test-plan.md.
Treat sections marked Normative as the required contract for agent execution.
Treat sections marked Reference as supporting material, examples, or quick navigation aids.
Normative sections in this file:
Normative defaults for agents
Normative rules
Normative command patterns for agents
Normative stdin contracts
Normative execution policy for autonomous agents
Normative error handling
Reference sections in this file:
Reference: preferred installation
Reference: required inputs
Reference: launch modes
Reference: decision guide
Reference: end-to-end agent scenarios
Reference: command-specific notes and examples
Reference: recommended agent workflow
Reference: known limitations
Reference: contributing
When the task requires executing eppie-console, use these defaults unless the task explicitly requires otherwise:
--non-interactive=true
--output=json for agent automation unless text output is explicitly required
--unlock-password-stdin=true for stateful commands that need an existing vault
--assume-yes=true for destructive automation
stdin exactly in the required order
Canonical command patterns and exact stdin contracts are defined later in this file. Use those sections as the single source of truth for agent execution.
eppie-console
eppie-console
eppie-cli-agent-test-plan.md
Prefer the executable published in GitHub Releases.
You can also build from source.
Latest release page:
Direct download links:
After extracting the archive, use the eppie-console executable directly.
eppie-console
-a; for agent workflows, use the account address string returned by list-accounts in data[].address
id
pk
Use only when a REPL session is explicitly needed.
Example:
eppie-console
Typical sequence:
open
list-accounts
exit
open is useful in interactive mode to open the local vault inside the current process.
Prefer this mode for agents.
Use:
eppie-console --non-interactive=true [command options]
To avoid passing the same startup flags on every call, you can put them in appsettings.json next to eppie-console, for example:
{ "non-interactive": true, "output": "json", "unlock-password-stdin": true }
eppie-console also reads configuration from environment variables.
When the default .NET host configuration pipeline is used, environment variables override appsettings.json. Command-line arguments override both.
For structured machine-readable output, also use:
--output=json
JSON responses use a normalized envelope:
type: result, status, warning, or error
code: stable machine-readable outcome code
data: payload for result and status responses
meta: optional metadata for result responses; usually null, but paged read commands can return objects such as {"header":"All messages:","returned":5,"hasMore":true}
message: human-readable warning/error text
In --non-interactive=true --output=json mode, structured responses are emitted on stdout without a preceding stack trace on stderr for handled command failures such as unhandledException.
In non-interactive mode, do not use open as part of the agent workflow. It does not establish reusable state for later process launches. For stateful non-interactive commands, use --unlock-password-stdin=true instead.
For all agent examples in this file, means the account address returned by list-accounts in data[].address. Prefer that address string for -a instead of the numeric id, unless a command explicitly documents another identifier format.
Common success-output examples:
--non-interactive=true --output=json list-accounts (with accounts):
{"type":"result","code":"accounts","data":[{"id":1,"address":"","accountType":"Dec"}],"meta":null}
--non-interactive=true --assume-yes=true --output=json reset:
{"type":"status","code":"reset","data":null}
--non-interactive=true --unlock-password-stdin=true --output=json send ...:
{"type":"status","code":"messageSent","data":{"subject":"","to":"","from":""}}
--non-interactive=true --unlock-password-stdin=true --output=json sync-folder ...:
{"type":"status","code":"folderSynced","data":{"account":"","folder":"Inbox"}}
--non-interactive=true --unlock-password-stdin=true --output=json show-all-messages ...:
{"type":"result","code":"messages","data":[{"id":1,"pk":1,"to":[""],"from":[""],"folder":"Inbox","subject":""}],"meta":{"header":"All messages:","returned":1,"hasMore":false}}
Additional command-specific JSON result shapes are documented later in Reference: command-specific notes and examples.
Common text success-output examples:
open:
The application was opened successfully.
reset:
The application has just been reset.
add-account -t dec:
Account added (Dec).
send:
Message sent from to . Subject:
sync-folder -f Inbox:
Folder 'Inbox' for account synchronized.
Normative command patterns for agents and Normative stdin contracts as normative for agent workflows.
-- and put the startup command after --.
open creates a reusable session for future process launches.
list-folders first.
-l / --limit when predictable payload size matters.
eppie-console open only opens the vault inside the current process.
It does not create a reusable session for future process launches.
Use this section as the single source of truth for agent command lines. Unless text output is explicitly required, all agent examples below use --output=json.
| Task | Canonical command |
| --- | --- |
| Initialize a vault | --non-interactive=true --output=json -- init |
| List accounts | --non-interactive=true --unlock-password-stdin=true --output=json -- list-accounts |
| List folders | --non-interactive=true --unlock-password-stdin=true --output=json -- list-folders -a |
| Show all messages | --non-interactive=true --unlock-password-stdin=true --output=json -- show-all-messages -s 10 -l 10 |
| Show one message | --non-interactive=true --unlock-password-stdin=true --output=json -- show-message -a |
| Delete one message | --non-interactive=true --unlock-password-stdin=true --output=json -- delete-message -a |
| List contacts | --non-interactive=true --unlock-password-stdin=true --output=json -- list-contacts -s 10 -l 10 |
| Show contact messages | --non-interactive=true --unlock-password-stdin=true --output=json -- show-contact-messages -c |
| Show folder messages | --non-interactive=true --unlock-password-stdin=true --output=json -- show-folder-messages -a |
| Sync a folder | --non-interactive=true --unlock-password-stdin=true --output=json -- sync-folder -a |
| Send a message | --non-interactive=true --unlock-password-stdin=true --output=json -- send -s |
| Reset local data | --non-interactive=true --assume-yes=true --output=json -- reset |
| Add a DEC account | --non-interactive=true --unlock-password-stdin=true --output=json -- add-account -t dec |
| Add a regular IMAP/SMTP account | --non-interactive=true --unlock-password-stdin=true --output=json -- add-account -t email --input-json-stdin |
| Add a Proton Mail account | --non-interactive=true --unlock-password-stdin=true --output=json -- add-account -t proton --input-json-stdin |
Provide stdin exactly in the documented order. Unless a command explicitly reads until end-of-stream, stop after the documented input has been written.
| Command | Exact stdin contract | EOF required |
| --- | --- | --- |
| --non-interactive=true --output=json -- init | line 1: new vault password | no |
| --non-interactive=true --unlock-password-stdin=true --output=json -- list-accounts | line 1: vault password | no |
| --non-interactive=true --unlock-password-stdin=true --output=json -- list-folders -a | line 1: vault password | no |
| --non-interactive=true --unlock-password-stdin=true --output=json -- show-all-messages -s | line 1: vault password | no |
| --non-interactive=true --unlock-password-stdin=true --output=json -- show-message -a | line 1: vault password | no |
| --non-interactive=true --unlock-password-stdin=true --output=json -- delete-message -a | line 1: vault password | no |
| --non-interactive=true --unlock-password-stdin=true --output=json -- list-contacts -s | line 1: vault password | no |
| --non-interactive=true --unlock-password-stdin=true --output=json -- show-contact-messages -c | line 1: vault password | no |
| --non-interactive=true --unlock-password-stdin=true --output=json -- show-folder-messages -a | line 1: vault password | no |
| --non-interactive=true --unlock-password-stdin=true --output=json -- sync-folder -a | line 1: vault password | no |
| --non-interactive=true --unlock-password-stdin=true --output=json -- send -s | line 1: vault password; line 2 and later: message body; then close stdin | yes |
| --non-interactive=true --assume-yes=true --output=json -- reset | no stdin | no |
| --non-interactive=true --unlock-password-stdin=true --output=json -- add-account -t dec | line 1: vault password | no |
| --non-interactive=true --unlock-password-stdin=true --output=json -- add-account -t email --input-json-stdin | line 1: vault password; remaining bytes: one JSON object | yes |
| --non-interactive=true --unlock-password-stdin=true --output=json -- add-account -t proton --input-json-stdin | line 1: vault password; remaining bytes: one JSON object | yes |
| Command group | Needs existing vault | Use --unlock-password-stdin=true | Prefer --output=json | Notes |
| --- | --- | --- | --- | --- |
| init | no | no | yes for agent workflows | writes a new local vault password from stdin |
| reset | no | no | yes | destructive; also use --assume-yes=true |
| list-accounts, list-folders | yes | yes | yes | inspect vault content |
| show-all-messages, show-message, show-folder-messages, show-contact-messages | yes | yes | yes | use -l when payload size matters |
| sync-folder | yes | yes | yes | call before reading when fresh messages are required |
| send | yes | yes | yes | password first in stdin, then body until EOF |
| add-account -t dec | yes | yes | yes | simple vault-backed account creation |
| add-account -t email, add-account -t proton | yes | yes | yes | use --input-json-stdin; do not pass secrets in arguments |
open in a non-interactive workflow.
list-folders first.
-l when an agent needs a predictable maximum payload size.
Normative defaults for agents defaults unless the task explicitly requires otherwise.
type, code, data, meta, and message from the normalized envelope.
warning and error responses as non-success outcomes even when the process exits cleanly.
Normative stdin contracts exactly.
send, close stdin after the last body line.
--input-json-stdin, pass the password first when required, then the JSON payload.
stdin contract.
list-accounts data[].address to -a.
id is accepted interchangeably by all commands.
list-accounts when a workflow depends on a newly created account.
-s / --page-size and -l / --limit in agent workflows when payload size must be predictable.
-s as page size only. Treat -l as the total maximum number of records returned by the command.
-l is omitted, paged read commands return up to 20 records by default.
meta.returned to confirm how many records were actually returned.
meta.hasMore to decide whether another read with a higher -l or a narrower filter is needed.
-l.
Use Normative command patterns for agents for the exact command line. This guide is only for choosing the next command.
list-accounts
list-folders
show-all-messages
list-folders, then sync-folder, then show-folder-messages when new messages are required
show-message
delete-message
list-contacts
show-contact-messages
send
list-folders, then sync-folder
init
reset
This section is informative. Use Normative command patterns for agents for the exact command line and Normative stdin contracts for the exact stdin shape.
Use this flow when the working directory does not yet contain the required local vault.
init
add-account
list-accounts
data[].address as in later commands
Typical sequences:
init → add-account -t dec → list-accounts
init → add-account -t email → list-accounts
init → add-account -t proton → list-accounts
Agent notes:
add-account -t email and add-account -t proton, provide the structured payload through standard input after the vault password as documented in Normative stdin contracts
list-accounts instead of assuming another identifier format
Use this flow when the task requires a concrete folder such as inbox or sent mail and the messages may have changed since the last sync.
list-accounts
list-folders
data[].fullName or data[].roles
sync-folder
show-folder-messages
show-message using its id and pk
Typical sequence:
list-accounts → list-folders → sync-folder → show-folder-messages → show-message
Agent notes:
fullName returned by list-folders
-s and -l on show-folder-messages when predictable payload size matters
meta.hasMore is true, treat the result as partial and increase -l only if the task requires a larger set
Use this flow when the local vault already contains the sender account and the task is to deliver one message deterministically.
list-accounts
data[].address
send with the sender, receiver, and subject
stdin line
stdin
Typical sequence:
list-accounts → send
Agent notes:
--non-interactive=true mode, send reads the body until end-of-stream, so the agent should close stdin after the last body line
--output=json and verify the messageSent status response instead of relying only on the process exit code
The canonical command lines are defined in Normative command patterns for agents, and the exact inputs are defined in Normative stdin contracts. This section keeps only command-specific notes, result shapes, and examples that are easy to reference during agent execution.
Notes:
stdin
Notes:
-s / --page-size controls only the page size
-l / --limit caps the total number of returned records and should be used by agents to keep payload size predictable
-l is omitted, paged read commands return up to 20 records by default
show-message: to and from are arrays
returned and hasMore
meta.hasMore before assuming the returned list is complete
Expected result shape:
{"type":"result","code":"folders","data":[{"fullName":"Inbox","unreadCount":0,"totalCount":0,"roles":["inbox"]}],"meta":{"account":""}}
Notes:
should be the account address from list-accounts data[].address
show-folder-messages or sync-folder instead of guessing provider-specific folder names
All Sent; rely on the returned fullName
roles when you need a machine-readable way to find folders such as inbox or sent mail
Notes:
Trash, the command moves the message to Trash
Trash, the command deletes it permanently
Notes:
returned and hasMore
Notes:
returned and hasMore
Expected result shape:
{"type":"status","code":"folderSynced","data":{"account":"","folder":"Inbox"}}
Examples:
vault password
Hello from automation
Second body line
stdin
Notes:
--non-interactive=true mode, send reads the message body until end-of-stream
{"type":"status","code":"messageSent","data":{"subject":"","to":"","from":""}}
PowerShell example with the command line and exact stdin in one block:
@"
vault password
Hello from automation
Second body line
"@ | .\eppie-console --non-interactive=true --unlock-password-stdin=true --output=json -- send -s sender@example.com -r receiver@example.com -t "Hello from automation"
Linux / bash example with the command line and exact stdin in one block:
cat <<'EOF_INPUT' | ./eppie-console --non-interactive=true --unlock-password-stdin=true --output=json -- send -s sender@example.com -r receiver@example.com -t "Hello from automation"
vault password
Hello from automation
Second body line
EOF_INPUT
Notes:
./eppie-console after extracting the archive and making sure the file is executable.
Use open only in interactive mode when the agent is already inside a REPL session and must open the local vault in that same process.
Notes:
open as part of the non-interactive agent workflow
Notes:
reset is a destructive command and should be called with --assume-yes=true in automation or other non-interactive scripts.
Expected result shape:
{"type":"result","code":"accountAdded","data":{"address":"","accountType":"Dec"},"meta":null}
Examples:
JSON object:
{
"email": "user@example.com",
"accountPassword": "account password",
"imapServer": "imap.example.com",
"imapPort": 993,
"smtpServer": "smtp.example.com",
"smtpPort": 465
}
stdin shape:
vault password
{"email":"user@example.com","accountPassword":"account password","imapServer":"imap.example.com","imapPort":993,"smtpServer":"smtp.example.com","smtpPort":465}
Notes:
email, accountPassword, imapServer, imapPort, smtpServer, and smtpPort
structuredStandardInputInvalidJson
structuredStandardInputMissingProperty
Examples:
JSON object:
{
"email": "user@proton.me",
"accountPassword": "account password",
"mailboxPassword": "mailbox password",
"twoFactorCode": "123456"
}
stdin shape:
vault password
{"email":"user@proton.me","accountPassword":"account password","mailboxPassword":"mailbox password"}
Notes:
email and accountPassword are required in structured input
mailboxPassword is required only if the Proton flow asks for it
twoFactorCode is required only if the Proton flow asks for it
mailboxPassword
structuredStandardInputInvalidJson
structuredStandardInputMissingProperty
Normative defaults for agents.
Normative command patterns for agents.
stdin in the exact shape defined in Normative stdin contracts.
list-accounts data[].address for -a.
list-folders if the next step requires a specific folder name,
show-all-messages when you need recent messages across all folders,
show-message or delete-message with the returned id and pk.
--non-interactive=true mode text output stops after the first page instead of prompting.
Reference: end-to-end agent scenarios as a quick reference.
--non-interactive=true suppresses interactive prompts, but it does not invent missing data.
Commands that normally ask follow-up questions still need explicit arguments or stdin data.
The main examples are already covered above:
send reads the message body until end-of-stream in --non-interactive=true mode
add-account -t email and add-account -t proton should use --input-json-stdin
reset still need --assume-yes=true
-l is omitted
For agent automation, prefer deterministic handling over implicit retries.
When --output=json is enabled, handle responses by type first:
| type | Meaning | Agent action |
| --- | --- | --- |
| result | command returned data | parse data and meta |
| status | command completed successfully without a list-style result | read data when present |
| warning | handled problem or non-success condition | inspect code; do not assume success; stop unless the workflow explicitly defines a recovery step |
| error | handled failure | inspect code, message, and data; stop unless the input can be corrected deterministically |
| code | Meaning | Typical agent response |
| --- | --- | --- |
| invalidPassword | vault password was rejected | stop; do not retry automatically with the same password |
| structuredStandardInputInvalidJson | structured payload is not valid JSON | fix serialization and retry once with corrected JSON |
| structuredStandardInputMissingProperty | required JSON property is missing or empty | provide the missing property and retry once |
| unhandledException | command failed and returned exception details | inspect data.exceptionType and command context; do not retry blindly |
type first, then code.
warning as success.
invalidPassword automatically.
structuredStandardInputInvalidJson or structuredStandardInputMissingProperty, change only the invalid input and keep the command line unchanged.
unhandledException, record the command, the parsed code, and data.exceptionType when present.
meta.hasMore: true, treat that as an incomplete result set rather than an error.
Invalid password example:
{"type":"warning","code":"invalidPassword","message":"Warning: Invalid password.","data":null}
Unknown sender account example for send:
{"type":"error","code":"unhandledException","message":"An error has occurred: ...","data":{"exceptionType":"Tuvi.Core.Entities.AccountIsNotExistInDatabaseException"}}
Invalid Proton structured input example:
{"type":"error","code":"structuredStandardInputInvalidJson","message":"Error: The remaining standard input for the 'add-account' command is not valid JSON.","data":{"commandName":"add-account"}}
Missing Proton structured property example:
{"type":"error","code":"structuredStandardInputMissingProperty","message":"Error: The structured standard input for the 'add-account' command must contain a non-empty 'email' property.","data":{"commandName":"add-account","propertyName":"email"}}
Contributions are welcome.
Please open issues for bugs, UX problems, and feature ideas.
Pull requests on GitHub are also welcome.
Repository:
共 1 个版本