Skip to content

Automation Environment Install and Configuration

This page explains how to get the mailagent CLI running inside CI / cron / an agent runner, and how to understand its configuration load order — the latter directly determines “whether the value I set actually took effect.”

The CLI is installed via pip’s optional-dependencies. From the repository root (with a venv already present), run:

Terminal window
source venv/bin/activate
pip install -e ".[cli,dev]"
# cli: typer / rich / pyyaml
# dev: pytest + jsonschema>=4.18 + referencing (needed for schema validation runs)

Verify:

Terminal window
which mailagent # should be <project>/venv/bin/mailagent
mailagent --version # prints the version number
mailagent --help # lists the 10 groups + global flags

At startup, the CLI loads configuration in the following order, with later sources overriding earlier ones:

PrecedenceSourceNotes
1 (lowest)~/.config/mailagent/config.tomlUser-level, optional
2<project>/.envThe pydantic Config shared with the service
3--config PATHConfig file explicitly specified on the CLI
4MAILAGENT_* environment variablese.g. MAILAGENT_CLI_API_KEY
5 (highest)Command-line flags--db-path / --api-key, etc.

Example: mailagent --config x.toml email get 53675 uses the db_path from x.toml rather than from .env.

Terminal window
# db-path override: temporarily point at another database (e.g. the app DB vs the main-repo PM2 DB)
mailagent --db-path ~/Library/Application\ Support/mailagent-frontend/data/sync_store.db \
-o json email list --limit 5
# API key override (write command): env beats .env, flag beats env
MAILAGENT_CLI_API_KEY=xxx mailagent email flag 53675 --is-read
mailagent --api-key xxx email flag 53675 --is-read

The load_cli_config() Factory — Why Configuration Is Guaranteed to Take Effect

Section titled “The load_cli_config() Factory — Why Configuration Is Guaranteed to Take Effect”

The CLI does not use a module-level singleton from src.config import config. The reason: pydantic Settings loads .env immediately at import time, which makes the --config flag arrive too late to override it.

The CLI instead uses an explicit factory, load_cli_config(config_path, env_overrides, flag_overrides): it reconstructs a fresh Config instance at every startup following the precedence chain above. This means:

  • The --config / --db-path / --api-key you pass are guaranteed to take effect and won’t be overridden by an import-time-locked .env.
  • Server-side processes (main.py / pm2) still use the global singleton and don’t interfere with the CLI path — the CLI is a short-lived process that loads cleanly each time.

Write commands require authentication (read commands do not). In an automation environment, inject it via an environment variable — don’t put it on the --api-key command line (which ends up in shell history / the process list):

Terminal window
# CI / cron: inject the env var from the secret store
export MAILAGENT_CLI_API_KEY="$(cat /run/secrets/mailagent_cli_key)"
mailagent email flag 53675 --is-read # automatically uses the key from env

The server-side .env also sets a MAILAGENT_CLI_API_KEY of the same name, and the CLI compares them with hmac.compare_digest. For the full rules (list of read/write commands, --dry-run skipping auth, dev-bypass risk), see Write-Command Authentication Contract.

mailagent is built on typer and ships shell completion:

Terminal window
# install completion for the current shell (zsh / bash / fish)
mailagent --install-completion zsh
# or just print the completion script and decide how to source it yourself
mailagent --show-completion zsh

Completion covers resources, actions, and flags, and is enumerable — this is exactly the autocomplete dividend that design principle 2, “resource-action consistency,” gives agents.

SymptomCauseFix
mailagent: command not foundvenv not activated / PATH doesn’t include venv/binsource venv/bin/activate or use the absolute path
Write command reports E_AUTH_FAILED (exit 4)MAILAGENT_CLI_API_KEY not passedInject the env var; see Authentication
Read command reports a SQLite permission errorMissing Full Disk AccessGrant FDA to the runner
admin db-version reports E_SCHEMA_MISMATCH (exit 5)db_version does not match expectedRun the backend first to apply DB migrations; see Exit Codes