bichon-cli — Import & Export
bichon-cli is a fully interactive menu-driven client that talks to a running Bichon server over its REST API. It takes a single option:
./bichon-cli # uses ./config.toml
./bichon-cli -c other.toml # alternate config fileConfiguration
On first run it prompts for the server Base URL and an API token, then offers to save them for future use. The config file is plain TOML:
base_url = "http://localhost:15630"
api_token = "…"Create a long-lived API token in the WebUI (Settings → API Tokens) or via POST /api/v1/access-token. The token's user needs the permissions for whatever you drive from the CLI (see below).
Import
After choosing a target account, pick one of four methods:
| Method | Description |
|---|---|
| EML Directory | Recursively scan a directory tree of .eml files; preserves folder structure |
| MBOX | Stream-import from a single .mbox archive (including Gmail's MBOX variant) |
| Thunderbird | Import directly from a local Thunderbird profile directory |
| PST | Import from Outlook Personal Storage .pst files |
Requirements specific to import:
- Only
nosync-type accounts can be import targets — accounts that archive from a live IMAP server are excluded, so an import can never race the sync pipeline. Create anosyncaccount in the WebUI first if you have none. See Accounts. - Your token's user needs
data:import:batchpermission on that account (or be an administrator withsystem:root). Accounts you cannot import into are shown as[NO PERMISSION].
Export
Three modes:
| Mode | Description |
|---|---|
| Export by saved search (recommended) | Pick a format first: Mbox (whole messages, needs an email saved search) or Attachments (a deduplicated zip, needs an attachment saved search). Then pick the saved search, preview the scope, confirm — the export runs as a server-side job and the CLI polls it and downloads the artifact |
| Export entire account (legacy) | Downloads every message in an account (100 per page) and writes the MBOX locally; shows account statistics first and checks free disk space with a 10% buffer |
| Verify an export job (compliance) | Verify a previously run export job — confirms the exported MBOX messages, or the zip's attachment hashes, match what the server holds |
Server-side jobs keep their artifact for one hour after finishing; download promptly. See Import & Export for the on-disk layout and limits.
All imports are processed server-side — the server handles MIME parsing, indexing, deduplication, and storage. The WebUI upload limits (1 GB MBOX / 2 GB PST) do not apply to the CLI path; for larger archives use bichon-cli.
bichon-admin — Administration
./bichon-adminbichon-admin is a separate binary from the server — it is not built by the server build. The Community workspace produces it with cargo build --release -p bichon-admin; on the Pro/Enterprise tree the same command is cargo build --release -p bichon-pro --bin bichon-admin, which builds the extended variant described at the end of this section.
Interactive menu with five operations:
| Operation | Description |
|---|---|
| Reset Admin Password | Reset the built-in admin password when locked out |
| Migrate v0.3.7 → v2.x | Non-destructive migration from legacy Tantivy-based storage to v2.x — see the step-by-step guide |
| Migrate v1.x → v2.x | Blob-only migration from Fjall to bichon-blob (indexes and metadata untouched) — see the step-by-step guide |
| Restore a Backup Point | Disaster recovery — restore a backup point into an empty directory |
| Rebuild Search Indexes | Rebuild the Tantivy indexes after an index-format change — see Rebuild Search Indexes |
Rebuild search indexes (reindex)
Releases that change the search index format require a one-time rebuild. It can be run non-interactively — pass --yes to skip the confirmation prompt, which is required when stdin is not a terminal (init containers, Kubernetes Jobs, CI):
./bichon-admin reindex --yes --bichon-root-dir /var/lib/bichonWithout a terminal and without --yes, the command refuses with exit code 2 instead of rebuilding (it no longer silently cancels with exit code 0). --yes only skips the confirmation — all pre-checks still run.
Use --bichon-index-dir / --bichon-data-dir (or BICHON_INDEX_DIR / BICHON_DATA_DIR) when the server was started with custom directories — they take the same parent paths. The command keeps the previous index as <index-parent>/bichon-indices.old-<timestamp> and never deletes it, so a failed or unsatisfactory rebuild can be rolled back. The full procedure, directory layout and rollback steps are on the Rebuild Search Indexes page.
Disaster-recovery restore (non-interactive)
The restore can also run without the menu, which is what you want on a fresh recovery box and in scripts:
./bichon-admin restore --config restore-config.json --into /path/to/empty-dir| Flag | Env equivalent | Description |
|---|---|---|
--config (-c) | — | Required. JSON config file describing the backup target (S3-compatible store or local directory) |
--into | BICHON_RESTORE_INTO | Required. Empty target directory to restore into |
--point | BICHON_RESTORE_POINT | Restore point to use — a manifest id, the object name from the target listing (m-<id> / m-<id>.json.gz), or LATEST (default: LATEST) |
--index-dir | BICHON_RESTORE_INDEX_DIR | Target Tantivy index parent dir (default <into>/bichon-indices) |
--data-dir | BICHON_RESTORE_DATA_DIR | Target blob data parent dir (default <into>/bichon-storage) |
--root-dir | BICHON_ROOT_DIR | Live data root of an existing install on the same box, if any — restore targets are refused if they touch it |
--bichon-restore-verify-only | — | Verify every object of the restore point against its manifest and write nothing (Pro build only) |
Omitting --point restores the latest committed backup point — there is no need to pass --point LATEST. To restore an older point, take the id of its manifest object from the backup target (<prefix>/v1/meta/m-<id>.json.gz) and pass it, e.g. --point 0192a1b2-c3d4-7e5f-8a9b-0c1d2e3f4a5b.
--bichon-restore-verify-only is a flag, not a subcommand — it is still a restore, and it writes nothing, so --into is not required with it. That makes it the safe way to answer "is this backup actually restorable?" before committing to a recovery. It exists only in the Pro build.
The config file describes which target to read the restore point from. target_type defaults to "s3", so a file written before local targets existed keeps working unchanged.
S3-compatible store — only s3_endpoint and s3_bucket are mandatory. Read-only credentials are sufficient for a restore: it only issues GET requests against the bucket. Write access is needed for backups themselves (object uploads, retention pruning), not for restoring from them.
{
"s3_endpoint": "https://s3.example.com",
"s3_bucket": "bichon-backups",
"prefix": "mail-archive",
"s3_region": "eu-west-1",
"s3_access_key": "…",
"s3_secret_key": "…"
}Local directory — the directory must exist and be mounted; a path whose volume is not attached is refused rather than silently read as an empty directory.
{
"target_type": "local",
"local_dir": "/mnt/backup",
"prefix": "mail-archive"
}prefix is the sub-location the restore points live under — the object-store prefix for an S3 target, the subdirectory of local_dir for a local one — and must match what the backups used. It defaults to bichon-backup.
Working out which directory is which
Both targets use the same layout, and it is worth knowing it, because a backup directory on disk does not tell you what to put in the config file by itself:
<local_dir>/ ← the "local_dir" you put in the config file
└── <prefix>/ ← the "prefix" (default: bichon-backup)
└── v1/
├── meta/ ← LATEST pointer, plus one m-<id>.json.gz manifest per restore point
└── obj/ ← immutable content-addressed objectsSo a directory that looks like /mnt/backup/bichon-backup/v1/meta/LATEST means local_dir: "/mnt/backup" with the default prefix — the bichon-backup component is the prefix, not part of the path. On an S3 target the same three levels sit inside the bucket, below the prefix.
To list the restore points you have, look in <local_dir>/<prefix>/v1/meta/ (or the equivalent prefix in the bucket): LATEST names the newest one, and each m-<id>.json.gz is one restore point whose id you can pass to --point.
Safety rules: the target directory must be empty and must never overlap the live data root of an existing install — a restore is only ever into a fresh location, which you then point Bichon at via BICHON_ROOT_DIR.
Note (Pro): The Pro build ships its own
bichon-adminwith the same CLI and menus, extended with the audit replayer (audit deltas are replayed on restore) and the--bichon-restore-verify-onlydrill flag. See Backup & Disaster Recovery (Pro).
"Restore" in Bichon — two different things
- Disaster-recovery restore (this subcommand): rebuild the entire archive — index, blobs, metadata — from a backup point into a fresh directory.
- Message restore (WebUI / REST): push archived messages back to their source IMAP server, e.g. after accidental deletion on the mail server. It is not an undo of deletion — deletes in Bichon are permanent, with no trash or recycle bin. See Introduction (Message Lifecycle).