Files
himalaya/CONTRIBUTING.md
T
Clément DOUIN 662bd26eb1 refactor: remove composer and reader
Composers and readers did not work as expected. It is just not possible for
himalaya to spawn a command that spawns $EDITOR, piping and redirection cannot
satisfy all the needs. Either the $EDITOR does not spawn (hangs over), either
himalaya does not collect any output from edition. The simplest way is to use an
intermediate temp file, or use process substitution. For eg., using mml:

  mml compose >(himalaya message send)

You can also write into a file then feed himalaya with it.
2026-06-01 16:27:54 +02:00

5.0 KiB

Contributing guide

Thank you for investing your time in contributing to Himalaya CLI.

Development environment

The development environment is managed by Nix flakes. Running nix develop (or nix-shell for non-flake users) spawns a shell with the right Rust toolchain, cargo-deny, pkg-config and the OpenSSL / DBus libraries.

If you do not want to use Nix, install rustup and pull the toolchain pinned by rust-version in Cargo.toml:

rustup update
  • cargo (>= v1.87)
  • rustc (>= v1.87, edition 2024)

Build

cargo build

You can disable default features with --no-default-features and enable individual features with --features feat1,feat2.

For example, an IMAP+SMTP-only release build:

cargo build --no-default-features --features imap,smtp,rustls-ring --release

The release profile ([profile.release] in Cargo.toml) sets lto = "fat", codegen-units = 1, strip = "symbols" and panic = "abort" to keep the binary small.

Project layout

Himalaya CLI is the command-line front-end of the Pimalaya project. Most of the work happens in companion crates rather than in this repository:

  • io-email: cross-protocol email client (EmailClientStd, shared Envelope / Mailbox / Flag / Address types, search DSL).
  • io-imap, io-jmap, io-maildir, io-smtp: per-protocol I/O-free coroutines plus the std-blocking clients that drive them.
  • io-http: I/O-free HTTP request/response state machines used by JMAP and the discovery wizard.
  • pimconf: PIM service discovery (PACC, Thunderbird Autoconfiguration, RFC 6186 SRV) consumed by the wizard.
  • pimalaya/stream: TCP / TLS / SASL plumbing shared by all std clients.
  • pimalaya/cli: cross-binary CLI helpers (printer, prompt, wizard primitives, clap args, build-time env, spinner).
  • pimalaya/config: TOML configuration loader and shell-expanded secrets.
  • pimalaya/mml: MIME Meta Language composer / interpreter, chained into messages send / messages add via a tempfile or shell process substitution.
  • pimalaya/sirup: session re-use over a Unix socket (pair with imap.server / smtp.server to amortize TLS handshakes).
  • pimalaya/ortie: standalone OAuth 2.0 token broker (replaces v1's bundled oauth-lib).
  • pimalaya/mimosa: standalone secret manager (replaces v1's bundled keyring-lib).

Bugs touching protocol semantics usually live in the matching io-* crate; rendering, composition and CLI surface live here.

Override dependencies

Cargo.toml already patches every Pimalaya crate to its git remote so the working copy compiles against the latest master of each lib:

[patch.crates-io]
io-email.git = "https://github.com/pimalaya/io-email"
io-http.git = "https://github.com/pimalaya/io-http"
io-imap.git = "https://github.com/pimalaya/io-imap"
io-jmap.git = "https://github.com/pimalaya/io-jmap"
io-maildir.git = "https://github.com/pimalaya/io-maildir"
io-smtp.git = "https://github.com/pimalaya/io-smtp"
pimalaya-cli.git = "https://github.com/pimalaya/cli"
pimalaya-config.git = "https://github.com/pimalaya/config"
pimalaya-stream.git = "https://github.com/pimalaya/stream"
pimconf.git = "https://github.com/pimalaya/pimconf"

To build against a local checkout of one of those crates, swap the matching .git = "..." for .path = "../<repo>". For example, with io-email next to himalaya:

[patch.crates-io]
io-email.path = "../io-email"

If cargo complains about "perhaps two different versions of crate X are being used", patch every Pimalaya crate that pulls X transitively so the dep graph converges on the local copies:

[patch.crates-io]
io-email.path = "../io-email"
io-http.path = "../io-http"
io-imap.path = "../io-imap"
io-jmap.path = "../io-jmap"
io-maildir.path = "../io-maildir"
io-smtp.path = "../io-smtp"
pimalaya-cli.path = "../cli"
pimalaya-config.path = "../config"
pimalaya-stream.path = "../stream"
pimconf.path = "../pimconf"

Lint, test, audit

cargo fmt
cargo clippy --all-features --all-targets
cargo test --all-features
cargo deny check

cargo deny runs against the rules in deny.toml (license allow-list and allowed git sources).

Commit style

Himalaya CLI follows the conventional commits specification. Prefix every commit with one of feat, fix, refactor, docs, chore, test, ci, build, optionally scoped (fix(imap): ...).