Quick start

From a clone to a synchronized local inbox. Every command and output below was executed against version 0.2.0 in an isolated state directory, with --skarbiec-bin pointed at a stand-in Skarbiec CLI that serves one documented bundle item (tea

Overview#

From a clone to a synchronized local inbox. Every command and output below was executed against version 0.2.0 in an isolated state directory, with --skarbiec-bin pointed at a stand-in Skarbiec CLI that serves one documented bundle item (team-inbox) — the same JSON shapes a real Skarbiec emits. Your IDs and timestamps will differ. The full command surface is cli; the flag-free operator journey is onboarding.

Build#

Prerequisites: Rust 1.82+, a skarbiec executable, and a mailbox with IMAP over TLS and SMTP over STARTTLS or implicit TLS.

bash
git clone https://github.com/wisent-ai/skrzynka.git
cd skrzynka
cargo build
./target/debug/skrzynka version
json
{
  "product": "skrzynka",
  "source": "source-build",
  "version": "0.2.0"
}

Every command prints one JSON object on stdout and exits 0, or one normalized error envelope on stderr and exits nonzero — automation never parses decorative text.

Inspect the zero state#

status creates the state directory and database if missing, counts local resources, and probes whether skarbiec can be started. It resolves no credential and touches no provider.

console
$ skrzynka --database "$STATE/skrzynka.db" status
{
  "product": "skrzynka",
  "version": "0.2.0",
  "database_path": "/var/folders/.../skrzynka-docs.15ebyxek/state/skrzynka.db",
  "schema_version": 4,
  "mailbox_count": 0,
  "enabled_mailbox_count": 0,
  "message_count": 0,
  "poll_interval_seconds": 60,
  "skarbiec_available": true
}

Without --database the default is ~/.local/share/skrzynka/skrzynka.db; without --skarbiec-bin the default is skarbiec on PATH (configuration).

Declare one mailbox in Skarbiec#

Skarbiec owns the mailbox list. Tag one item skrzynka:mailbox; a complete bundle supplies everything, and only non-secret fields are persisted by Skrzynka:

bash
skarbiec retag team-inbox --tags skrzynka:mailbox
skrzynka --database "$STATE/skrzynka.db" mailbox list

mailbox list reads the declaration and prints the mailbox that stands for the item: its UUID, skarbiec_item_id, the address and servers from the item, enabled: true, and last_uid: 0. No password or username appears — the row references its receiving item and, only when configured, a separate sending item; each secret is resolved only while its protocol connection is open. Missing source data is reported under reconciliation.refused by sync and never replaced by defaults. skrzynka mailbox declare --skarbiec-item team-inbox does the tagging itself and also imports every INBOX message.

Synchronize and read#

bash
skrzynka --database "$STATE/skrzynka.db" sync
skrzynka --database "$STATE/skrzynka.db" message list

Against a reachable mailbox, sync prints one result per enabled mailbox with a summary of received, skipped, and the advanced last_uid cursor, and message list shows the normalized messages (sender, subject, snippet, plain-text body). This isolated lab deliberately has no reachable IMAP endpoint, so the same commands return the exact failure shape you will meet in real operations — per-mailbox, normalized, and non-fatal to other mailboxes:

json
{
  "completed_at": "2026-08-24T23:09:24.159599+00:00",
  "mailboxes": [
    {
      "mailbox_id": "3a9f65f0-a6e1-4520-bd35-708731a6a92f",
      "ok": false,
      "summary": null,
      "error_code": "IMAP_UNAVAILABLE",
      "error_message": "IMAP server could not be reached over TLS"
    }
  ]
}

The failure is also recorded on the mailbox (last_error_code, last_error_message) where mailbox show <id> and the desktop find it. Every code and its fix: runbook.

Serve the loopback API#

console
$ skrzynka --database "$STATE/skrzynka.db" serve --bind 127.0.0.1:8791
2026-08-24T23:09:52.159767Z  INFO skrzynka: Skrzynka API ready address=127.0.0.1:8791

serve starts the IMAP IDLE watchers and the authenticated JSON API used by skrzynka-desktop. Only loopback binds are accepted. Health needs no session:

console
$ curl -s http://127.0.0.1:8791/healthz
{"status":"ready","product":"skrzynka","version":"0.2.0","schema_version":4}

Everything under /v1 requires a Wisent bearer and organization header and fails closed without them (API, walkthrough).

Reply when you mean it#

bash
skrzynka --database "$STATE/skrzynka.db" message reply <message-uuid> --body-file reply.txt

The reply goes out through the mailbox that received the message, as a plain-text Re: with thread headers preserved. The body file must be UTF-8; its size is the SMTP server's to accept or refuse. Omitting --idempotency-key generates a fresh UUID; supply your own key when a retrying script must never double-send (reply attempt).

Clean up#

bash
skrzynka --database "$STATE/skrzynka.db" mailbox remove <mailbox-uuid> --confirm

Removal cascades through local messages, reply records and the outbound messages that mailbox originated; the Skarbiec item and the provider mailbox are untouched. The captured end-to-end sequence, including every refusal on the way, is walkthrough-local-lifecycle.