Skip to content
GitHub stars

CLI Reference

Global Flags

FlagDescription
--configPath to config file (default: ~/.msgvault/config.toml)
--homeHome directory for all data (overrides MSGVAULT_HOME)
-v, --verboseVerbose output (implies --log-level=debug)
--localForce local database mode when [remote] is configured
--log-file <path>Override log file path (default: <data_dir>/logs/msgvault-YYYY-MM-DD.log)
--log-level <level>Log level: debug, info, warn, error (default: info)
--no-log-fileDisable file logging for this run (stderr output stays on)
--log-sqlLog every SQL query at info level (verbose, for debugging)
--log-sql-slow-ms <ms>Slow query threshold in ms (default: 100; 0 uses built-in default)
--helpShow help

init-db

Initialize the SQLite database.

Terminal window
msgvault init-db

add-account

Add a Gmail account and authorize via OAuth.

Terminal window
msgvault add-account <email>
msgvault add-account <email> --headless
msgvault add-account <email> --oauth-app <name>
FlagDescription
--headlessShow instructions for headless server setup
--oauth-appUse a named OAuth app from [oauth.apps.<name>] in config
--forceDelete existing token and re-authorize
--display-nameSet a display name for the account
--no-default-identityDo not auto-confirm the email address as this account’s “me” identity

If [oauth].service_account_key or [oauth.apps.<name>].service_account_key is configured, add-account authorizes via Google service account domain-wide delegation instead of browser OAuth. Service-account accounts do not use --headless or --force.


add-imap

Add an IMAP account for syncing mail from any standard IMAP server.

Terminal window
msgvault add-imap --host <hostname> --username <email>

The command prompts interactively for your password (never accepted as a flag to avoid shell history exposure). For scripting or Docker, set MSGVAULT_IMAP_PASSWORD or pipe via stdin:

Terminal window
MSGVAULT_IMAP_PASSWORD="..." msgvault add-imap --host imap.example.com --username [email protected]
# or
echo "$PASS" | msgvault add-imap --host imap.example.com --username [email protected]

It tests the connection before saving credentials.

FlagDefaultDescription
--host(required)IMAP server hostname
--username(required)IMAP username or email address
--port993IMAP server port (993 for TLS, 143 for STARTTLS/plain)
--starttlsfalseUse STARTTLS instead of implicit TLS
--no-tlsfalseDisable TLS entirely (plaintext, not recommended)
--no-default-identityfalseDo not auto-confirm the username as this account’s “me” identity

Credentials are stored in tokens/imap_<hash>.json with restricted file permissions (0600). Use app-specific passwords when your provider supports them.

After adding an account, sync it with msgvault sync-full. IMAP accounts use the same sync and sync-full commands as Gmail. See Setup Guide for a walkthrough.


add-o365

Add a Microsoft 365 or Outlook.com account via OAuth2 with XOAUTH2 IMAP authentication.

Terminal window
msgvault add-o365 <email>

The command opens your browser for Microsoft OAuth consent, then configures IMAP with XOAUTH2 automatically. The correct IMAP host is auto-detected: outlook.office.com for personal accounts (hotmail.com, outlook.com, live.com, msn.com) and outlook.office365.com for organizational accounts.

Requires a [microsoft] section with client_id in config.toml. See the OAuth Setup guide for Azure AD app registration.

FlagDefaultDescription
--tenantcommonAzure AD tenant ID (restricts which accounts can authorize)
--no-default-identityfalseDo not auto-confirm the email address as this account’s “me” identity

After adding the account, sync it with msgvault sync-full.


sync-full

Download all messages from a Gmail or IMAP account. When called without an email argument, syncs all configured syncable accounts.

Terminal window
msgvault sync-full [email] [flags]
FlagDescription
--limit NMaximum messages to download
--after YYYY-MM-DDOnly messages after this date
--before YYYY-MM-DDOnly messages before this date
--queryGmail search query filter
--noresumeIgnore checkpoints, start fresh
--verboseDetailed progress output

sync

Sync new and changed messages. Gmail accounts use the Gmail History API; IMAP accounts perform a mailbox scan and skip messages already in the database. When called without an email argument, syncs all accounts that have completed an initial full sync.

Terminal window
msgvault sync [email]

import-mbox

Import a local MBOX archive into msgvault.

Terminal window
msgvault import-mbox <identifier> <export-file>

The export file may be a plain mbox file (any extension) or a .zip containing one or more .mbox/.mbx files.

FlagDefaultDescription
--source-typemboxSource type recorded in database (e.g., hey for HEY.com)
--labelLabel(s) to apply to imported messages (repeatable, or comma-separated)
--no-resumefalseStart fresh, ignoring interrupted progress
--checkpoint-interval200Save progress every N messages
--no-attachmentsfalseSkip writing attachments to disk
--no-default-identityfalseDo not auto-confirm the identifier as this source’s “me” identity

See Importing Local Email for usage examples.


import-emlx

Import Apple Mail .emlx files into msgvault. Can auto-discover accounts from macOS Accounts4.sqlite or accept explicit arguments.

Terminal window
# Auto-discover accounts (reads ~/Library/Accounts/Accounts4.sqlite)
msgvault import-emlx
# Specify mail directory
msgvault import-emlx <mail-dir>
# Legacy form: explicit identifier and directory
msgvault import-emlx <identifier> <mail-dir>

The mail directory should be an Apple Mail mailbox tree containing .mbox or .imapmbox directories, each with a Messages/ subdirectory of .emlx files. You can also point directly at a single .mbox directory. Labels are derived from directory names.

FlagDefaultDescription
--source-typeapple-mailSource type recorded in database
--accountFilter to specific account(s) during auto-discover (repeatable)
--accounts-dbCustom path to macOS Accounts4.sqlite
--identifierManual identifier when auto-discover is not suitable
--no-resumefalseStart fresh, ignoring interrupted progress
--checkpoint-interval200Save progress every N messages
--no-attachmentsfalseSkip writing attachments to disk
--no-default-identityfalseDo not auto-confirm the identifier as this source’s “me” identity

See Importing Local Email for usage examples.


import-pst

Import a Microsoft Outlook PST archive into msgvault.

Terminal window
msgvault import-pst <identifier> <pst-file>

The importer preserves PST folder structure as labels, imports email messages, and skips non-email PST items such as calendar entries, contacts, tasks, and notes.

FlagDefaultDescription
--source-typepstSource type recorded in database
--skip-folderFolder name to skip, case-insensitive; repeat for multiple folders
--no-resumefalseStart fresh, ignoring interrupted progress
--checkpoint-interval200Save progress every N messages
--no-attachmentsfalseSkip writing attachments to disk

See Importing Local Email for usage examples.


import-whatsapp

Import messages from a decrypted WhatsApp msgstore.db SQLite database.

Terminal window
msgvault import-whatsapp <msgstore.db> --phone <your-number>

The --phone flag is required and must be in E.164 format (e.g., +447700900000).

FlagRequiredDescription
--phoneYesYour phone number in E.164 format (must start with +)
--contactsNoPath to contacts .vcf file for name resolution
--media-dirNoPath to decrypted Media folder for attachments
--limitNoLimit number of messages (for testing)
--display-nameNoDisplay name for the phone owner
--no-default-identityNoDo not auto-confirm the phone number as this source’s “me” identity

See Text Messages for usage examples.


import-imessage

Import messages from the local iMessage database on macOS. Requires Full Disk Access in System Settings.

Terminal window
msgvault import-imessage

Reads from ~/Library/Messages/chat.db by default. This is a read-only operation.

FlagDefaultDescription
--db-path~/Library/Messages/chat.dbPath to chat.db
--beforeOnly messages before this date (YYYY-MM-DD)
--afterOnly messages after this date (YYYY-MM-DD)
--limit0Limit number of messages (for testing)
--meYour phone/email for recipient tracking
--contactsPath to contacts .vcf file for display-name backfill

See Text Messages for usage examples.


import-gvoice

Import texts, calls, and voicemails from a Google Voice Takeout export.

Terminal window
msgvault import-gvoice <takeout-voice-dir>

The directory must be the “Voice” folder from a Google Takeout export, containing Calls/ and Phones.vcf.

FlagDefaultDescription
--beforeOnly messages before this date (YYYY-MM-DD)
--afterOnly messages after this date (YYYY-MM-DD)
--limit0Limit number of messages (for testing)
--no-default-identityfalseDo not auto-confirm the phone number as this source’s “me” identity

See Text Messages for usage examples.


import-messenger

Import Facebook Messenger conversations from a Download Your Information export.

Terminal window
msgvault import-messenger --me <[email protected]> <dyi-export-dir>
FlagDefaultDescription
--me(required)Your synthetic Messenger identifier, e.g. [email protected]
--formatautoExport format: auto, json, html, or both
--limit0Limit number of messages (for testing)
--no-resumefalseStart fresh, ignoring interrupted progress
--checkpoint-interval200Save progress every N messages

See Text Messages for usage examples.


import-synctech-sms

Import SMS Backup & Restore XML or ZIP backups.

Terminal window
msgvault import-synctech-sms <path> --owner-phone <your-number>
FlagDefaultDescription
--owner-phone(required)Your phone number in E.164 format
--smstrueImport SMS records
--mmstrueImport MMS records
--callstrueImport call logs
--attachmentstrueImport MMS attachments

See Text Messages for usage examples.


add-synctech-sms-drive

Configure a Google Drive source for SMS Backup & Restore backups.

Terminal window
msgvault add-synctech-sms-drive <name> --owner-phone <number> --folder-id <id> --google-account <email>
FlagDefaultDescription
--owner-phone(required)Your phone number in E.164 format
--folder-id(required)Google Drive folder ID containing backups
--google-account(required)Google account used for Drive access
--schedule30 4 * * *Cron schedule used by msgvault serve
--oauth-appNamed Google OAuth app to use

sync-synctech-sms

Run one configured SMS Backup & Restore source immediately.

Terminal window
msgvault sync-synctech-sms <name>

Search the archive with Gmail-like query syntax. Supports keyword (FTS5), semantic, and hybrid modes.

Terminal window
msgvault search <query> [flags]
FlagDescription
-n, --limit NMaximum number of results (default: 50)
--offset NSkip first N results (only valid for --mode fts)
--jsonOutput results as JSON
--accountLimit results to a specific account
--collectionLimit results to all member accounts of a collection
--modeSearch mode: fts (default), vector, or hybrid. vector and hybrid require vector search to be configured.
--explainInclude per-signal scores (RRF, BM25, vector) in the output. Only applies to --mode vector and --mode hybrid.

--mode vector and --mode hybrid require at least one free-text term in the query (filter-only queries use --mode fts). They do not support pagination (--offset is rejected), so bump --limit to retrieve a larger candidate pool instead. See Searching for the operator reference and Vector Search for semantic setup.


tui

Launch the interactive terminal interface.

Terminal window
msgvault tui [flags]
FlagDescription
--force-sqlForce SQLite queries instead of Parquet
--no-cache-buildSkip automatic cache build/update

export-eml

Export a message as a .eml file. Accepts either a numeric database ID or a Gmail message ID.

Terminal window
msgvault export-eml <id> [flags]
FlagDescription
-o, --output <path>Output file (default: <gmail_id>.eml, use - for stdout)

export-attachment

Export an attachment by its SHA-256 content hash.

Terminal window
msgvault export-attachment <content-hash> [flags]
FlagDescription
-o, --output <path>Output file path (use - for stdout)
--base64Output raw base64 to stdout
--jsonOutput as JSON with base64-encoded data

The --json, --base64, and --output flags are mutually exclusive.

See Exporting Data for usage examples.


export-attachments

Export all attachments from a message as individual files.

Terminal window
msgvault export-attachments <message-id> [flags]
FlagDescription
-o, --output <dir>Output directory (default: current directory)

Accepts internal numeric IDs or Gmail message IDs. See Exporting Data for usage examples.


export-token

Export a browser-created OAuth refresh token to a remote msgvault instance.

Use this for headless deployments (NAS, cloud VM, any remote server) that cannot run a browser flow.

Terminal window
msgvault export-token <email> [flags]
FlagDescription
--to <url>Remote msgvault URL (or MSGVAULT_REMOTE_URL)
--api-key <key>API key (or MSGVAULT_REMOTE_API_KEY)
--allow-insecureAllow HTTP for trusted networks (for example Tailscale)

export-token uploads ~/.msgvault/tokens/<email>.json to /api/v1/auth/token/<email>, saves it in the remote token store, and posts account metadata to /api/v1/accounts.


verify

Verify local archive integrity against Gmail.

Terminal window
msgvault verify <email> [flags]
FlagDescription
--sample NMessages to sample (default: 100)

stats

Show archive statistics.

Terminal window
msgvault stats [flags]
FlagDescription
--accountShow stats for a specific account
--collectionShow stats for all member accounts of a collection

identity

Manage the confirmed “me” identifiers for each account.

Terminal window
msgvault identity list [flags]
msgvault identity show <account> [flags]
msgvault identity add <account> <identifier> [flags]
msgvault identity remove <account> <identifier>
CommandDescription
identity listList confirmed identifiers across accounts
identity show <account>Show one account’s identity in detail
identity add <account> <identifier>Add a confirmed identifier
identity remove <account> <identifier>Remove a confirmed identifier
FlagApplies toDescription
--accountlistRestrict to a single account
--collectionlistRestrict to all member accounts of a collection
--jsonlist, showOutput as JSON
--signaladdEvidence signal name (default manual)

collection

Manage named groups of accounts.

Terminal window
msgvault collection create <name> --accounts <account1,account2,...>
msgvault collection list
msgvault collection show <name>
msgvault collection add <name> --accounts <account1,account2,...>
msgvault collection remove <name> --accounts <account1,account2,...>
msgvault collection delete <name>

Deleting a collection does not delete sources or messages.


deduplicate

Find and merge duplicate messages within an account or collection.

Terminal window
msgvault deduplicate [flags]

By default, each source is deduplicated independently. --collection is the explicit opt-in for cross-source deduplication.

FlagDescription
--dry-runScan and report only; do not hide duplicates
--accountScope dedup to one account
--collectionDedup across every member account of a collection
--content-hashAlso detect duplicates by normalized raw MIME content
--preferComma-separated source type preference order
--undo <batch-id>Restore rows hidden by a previous dedup run; repeatable
--delete-dups-from-source-serverStage same-source pruned duplicates for remote deletion
--no-backupSkip the database backup before merging
-y, --yesSkip confirmation prompt

delete-deduped

Permanently delete dedup-hidden messages from the local archive.

Terminal window
msgvault delete-deduped --batch <batch-id>
msgvault delete-deduped --all-hidden

This is local-only and cannot be undone with deduplicate --undo.

FlagDescription
--batchDelete rows hidden by this dedup batch ID; repeatable
--all-hiddenDelete every dedup-hidden row regardless of batch
--no-backupSkip database backup before deleting
-y, --yesSkip confirmation prompt (--all-hidden still prompts)

list-senders

List top senders by message count.

Terminal window
msgvault list-senders [flags]
FlagDescription
-n, --limit NNumber of results (default: 50)
--after YYYY-MM-DDOnly messages after this date
--before YYYY-MM-DDOnly messages before this date
--jsonOutput as JSON

list-domains

List top sender domains by message count.

Terminal window
msgvault list-domains [flags]
FlagDescription
-n, --limit NNumber of results (default: 50)
--after YYYY-MM-DDOnly messages after this date
--before YYYY-MM-DDOnly messages before this date
--jsonOutput as JSON

list-labels

List all labels with message counts.

Terminal window
msgvault list-labels [flags]
FlagDescription
-n, --limit NNumber of results (default: 50)
--after YYYY-MM-DDOnly messages after this date
--before YYYY-MM-DDOnly messages before this date
--jsonOutput as JSON

build-cache

Build or update the Parquet analytics cache.

Terminal window
msgvault build-cache [flags]
FlagDescription
--full-rebuildDiscard existing cache and rebuild

rebuild-fts

Rebuild the SQLite FTS5 search index.

Terminal window
msgvault rebuild-fts

Use this if verify reports FTS5 shadow-table corruption such as a malformed inverted index. The command rebuilds the search index from the canonical messages table.


embeddings

Manage the vector embedding index used by --mode vector and --mode hybrid search. Requires a build with sqlite_vec support (default via make build) and a configured [vector.embeddings] endpoint. See Vector Search for prerequisites, model rotation, and troubleshooting.

Terminal window
msgvault embeddings <subcommand> [flags]
SubcommandDescription
buildBuild or update the index. Incremental by default; --full-rebuild starts a new generation.
resumeDrain the pending queue for the building or active generation. Always incremental.
listList index generations with their state, model, dimension, and pending count.
activate <generation-id>Activate a completed building generation, retiring the current active one.
retire <generation-id>Retire a generation.

embeddings build

Terminal window
msgvault embeddings build [flags]
FlagDescription
--full-rebuildCreate a new index generation and rebuild from scratch. The new generation is activated atomically once pending work drains. Same-model rebuilds keep serving the previous active generation in the meantime; model or dimension changes return index_stale for vector/hybrid search until the new generation activates.
--yesSkip the confirmation prompt that --full-rebuild otherwise requires.

Without --full-rebuild, the command is incremental: it resumes any in-flight rebuild that matches the configured model, otherwise drains the pending queue for the active generation, then exits. Safe to schedule via cron (or let msgvault serve do it via [vector.embed.schedule]).

embeddings resume

Terminal window
msgvault embeddings resume

Drain the pending queue and finish the current generation. If a generation matching the configured model is building, this embeds its remaining rows and activates it once the queue reaches zero; otherwise it tops up the active generation. Equivalent to msgvault embeddings build with no flags, but never starts a full rebuild.

embeddings list

Terminal window
msgvault embeddings list

Print one row per index generation: ID, state (building, active, or retired), model, dimension, embedded message count, pending count, fingerprint, and the start, completion, and activation timestamps.

embeddings activate

Terminal window
msgvault embeddings activate <generation-id> [flags]

Activate a completed building generation and retire the currently active one. By default this refuses to activate a generation that still has pending rows, has not finished seeding, or whose fingerprint does not match the current config.

FlagDescription
--yesSkip the confirmation prompt.
--forceActivate even with pending rows or a fingerprint mismatch.

embeddings retire

Terminal window
msgvault embeddings retire <generation-id> [flags]

Mark a generation as retired. Retiring the active generation requires --force-active, since it leaves no generation serving vector/hybrid search.

FlagDescription
--yesSkip the confirmation prompt.
--force-activeAllow retiring the generation that is currently active.

msgvault build-embeddings remains as a deprecated alias for msgvault embeddings build (same --full-rebuild and --yes flags).


cache-stats

Show statistics about the analytics cache.

Terminal window
msgvault cache-stats

query

Run arbitrary SQL against the Parquet analytics cache using an in-memory DuckDB engine.

Terminal window
msgvault query <sql> [flags]

If the analytics cache is stale, it is automatically rebuilt before the query runs.

FlagDefaultDescription
--formatjsonOutput format: json, csv, or table

See SQL Queries for available views and example queries.


mcp

Start the Model Context Protocol server for AI assistant integration.

Terminal window
msgvault mcp [flags]
FlagDefaultDescription
--force-sqlfalseAlways use SQL retrieval instead of FTS5
--httpServe MCP over StreamableHTTP on this address instead of stdio. Bare ports bind to loopback, e.g. 8080 becomes 127.0.0.1:8080.
--http-allow-insecurefalseAllow non-loopback HTTP binding. The MCP server has no built-in auth; put it behind a trusted network or authenticated reverse proxy.

See MCP Server for configuration and tool reference.


serve

Start the web server with optional background sync scheduling.

Terminal window
msgvault serve

The serve command has no CLI flags. All configuration (port, bind address, API key, CORS, account schedules, SyncTech SMS sources, and vector embedding schedule) is read from your config.toml. See Web Server for endpoint documentation and Configuration for config options. When vector search is enabled, the daemon can also run the embed worker on a cron and/or after every successful sync, see Configuration: vector.embed.schedule.


setup

Run the first-run setup wizard for OAuth and optional remote deployment.

Terminal window
msgvault setup

If configured for a remote server, this command generates <MSGVAULT_HOME>/nas-bundle with:

  • config.toml ready for container deployment
  • client_secret.json
  • docker-compose.yml

The wizard also stores remote URL/API key in remote config block so export-token can use it without extra flags.


show-message

Show full message details.

Terminal window
msgvault show-message <id> [flags]
FlagDescription
--jsonOutput as JSON

list-accounts

List synced email accounts.

Terminal window
msgvault list-accounts [flags]
FlagDescription
--jsonOutput as JSON

update-account

Update account settings.

Terminal window
msgvault update-account <email> [flags]
FlagDescription
--display-nameSet a display name for the account

remove-account

Remove an account and all its local data. Deletes messages, labels, sync state, OAuth or IMAP credentials, and attachment files unique to this account. This is irreversible and operates only on the local archive; it does not touch the remote provider.

Terminal window
msgvault remove-account <email> [flags]
FlagDescription
-y, --yesSkip the confirmation prompt (and allow removal when an active sync is in progress)
--typeSource type to remove when the same identifier exists across source types (gmail, imap, mbox, etc.)

Attachment files are only deleted when no other account references the same content hash. The shared Parquet analytics cache is also cleared; run msgvault build-cache afterward to rebuild it.


list-deletions

List pending and recent deletion batches.

Terminal window
msgvault list-deletions

show-deletion

Show details of a deletion batch.

Terminal window
msgvault show-deletion <batch-id>

cancel-deletion

Cancel pending or in-progress deletion batches. When called without a batch ID, lists available batches.

Terminal window
msgvault cancel-deletion [batch-id]
msgvault cancel-deletion --all
FlagDescription
--allCancel all pending and in-progress batches

delete-staged

Execute staged remote deletions. By default, Gmail messages are moved to trash; pass --permanent for permanent Gmail batch deletion. IMAP deletion removes messages from the provider using IMAP delete/expunge behavior.

Terminal window
msgvault delete-staged [batch-id] [flags]
FlagDescription
-y, --yesSkip confirmation prompt
--permanentPermanently delete through the Gmail batch API instead of moving to trash
--dry-runShow what would be deleted without deleting
-l, --listList staged deletion batches
--accountFilter to a specific account

Execution requires MSGVAULT_ENABLE_REMOTE_DELETE=1. --list and --dry-run work without the gate. --permanent and --yes are mutually exclusive because permanent deletion always requires the destructive confirmation prompt.


repair-encoding

Fix UTF-8 encoding issues in existing messages.

Terminal window
msgvault repair-encoding

update

Update msgvault to the latest version.

Terminal window
msgvault update [flags]
FlagDescription
--checkCheck for updates without installing
-y, --yesSkip confirmation prompt
-f, --forceForce update even if already on the latest version

version

Print version, commit, build date, and platform information.

Terminal window
msgvault version

completion

Generate a shell completion script.

Terminal window
msgvault completion [bash|zsh|fish|powershell]

To load completions:

Bash:

Terminal window
source <(msgvault completion bash)
# Permanent (Linux):
msgvault completion bash > /etc/bash_completion.d/msgvault
# Permanent (macOS with Homebrew):
msgvault completion bash > $(brew --prefix)/etc/bash_completion.d/msgvault

Zsh:

Terminal window
msgvault completion zsh > "${fpath[1]}/_msgvault"

If shell completion is not already enabled, add autoload -U compinit; compinit to your ~/.zshrc first.

Fish:

Terminal window
msgvault completion fish > ~/.config/fish/completions/msgvault.fish

PowerShell:

Terminal window
msgvault completion powershell | Out-String | Invoke-Expression

logs

View and tail structured log files. File logging must be enabled first (see Configuration: Log).

Terminal window
msgvault logs [flags]
FlagDefaultDescription
-f, --followfalseFollow today’s log file as new lines are written
-n, --lines50Number of trailing lines to show before following
--run-id <id>Filter to a single run (matches on prefix)
--level <level>Filter by log level: debug, info, warn, error
--grep <string>Substring filter applied to the raw JSON record
--allfalseRead every log file in the logs directory, not just today’s
--pathfalsePrint the log directory path and exit

Examples:

Terminal window
# Last 50 lines of today's log
msgvault logs
# Follow live
msgvault logs -n 200 -f
# Filter to a single run by its correlation ID
msgvault logs --run-id a1b2c3
# Only errors
msgvault logs --level error
# Substring search across all log files
msgvault logs --all --grep deduplicate

quickstart

Print a quickstart guide for AI agents.

Terminal window
msgvault quickstart