[package] name = "openhuman" version = "0.63.9" edition = "2021" description = "OpenHuman core business logic and RPC server" autobins = false # build.rs globs tests/raw_coverage/*.rs into the single `raw_coverage_all` # integration target (see tests/raw_coverage_all.rs). Those files used to be ~76 # individual `tests/*.rs` targets, each statically relinking the whole crate — # collapsing them into one target removes ~75 full-crate link steps per test run. build = "build.rs" [[bin]] name = "openhuman-core" path = "src/main.rs" [[bin]] name = "slack-backfill" path = "src/bin/slack_backfill.rs" [[bin]] name = "gmail-backfill-3d" path = "src/bin/gmail_backfill_3d.rs" [[bin]] name = "memory-tree-init-smoke" path = "src/bin/memory_tree_init_smoke.rs" [[bin]] name = "inference-probe" path = "src/bin/inference_probe.rs" [[bin]] name = "harness-subagent-audit" path = "src/bin/harness_subagent_audit.rs" [[bin]] name = "test-mcp-stub" path = "src/bin/test_mcp_stub.rs" [[bin]] name = "openhuman-fleet" path = "src/bin/fleet.rs" # The fleet supervisor embeds the axum control-plane server, so it only builds # with the HTTP transport compiled in (#5048). Under `--no-default-features` # (no `http-server`) this target is skipped rather than failing to link. required-features = ["http-server"] # Embedded-RSS benchmark harness (#5046). Gated behind the default-OFF # `rss-bench` feature so no benchmark code enters the shipped build. Build with # `cargo build --release --features rss-bench --bin rss-bench`. [[bin]] name = "rss-bench" path = "src/bin/rss_bench.rs" required-features = ["rss-bench"] # Stateful library profiling workloads (memory ingestion + real sub-agent # delegation under a hermetic mock provider). Local/dev only. [[bin]] name = "library-profile" path = "src/bin/library_profile/main.rs" required-features = ["rss-bench"] [lib] name = "openhuman_core" crate-type = ["rlib"] [dependencies] # tinyhumans-sdk — the typed Rust client for the TinyHumans backend API # (https://github.com/tinyhumansai/sdk). Vendored as a git submodule under # `vendor/` beside the other tiny* crates and consumed by path: the crate is not # published to crates.io, so there is no `[patch.crates-io]` entry for it. # This is the single source of truth for backend routes — `src/api/` is the # OpenHuman-local adapter layer (session tokens, config, observability) that # sits on top of it, not a second HTTP client. Anything missing here belongs # upstream in the SDK repo, not re-implemented in `src/api/`. # After cloning: `git submodule update --init vendor/tinyhumans-sdk`. tinyhumans-sdk = { path = "vendor/tinyhumans-sdk" } # tiny.place A2A social network SDK — published on crates.io and patched below # to the vendored tiny.place submodule so OpenHuman can test SDK changes before # publishing. tinyplace = "2.0" # tinyflows — host-agnostic workflow engine (typed node graph → validate → compile → # run on tinyagents). Powers the "Workflows" feature via the seam in # `src/openhuman/tinyflows/` + the `flows::` domain. Pulls tinyagents 2.1 transitively # (same version OpenHuman uses directly, preserving one trait identity). Published # on crates.io and patched below to the vendored submodule. # # `mock` feature: enables `tinyflows::caps::mock::mock_capabilities()` — the # deterministic in-memory capability bundle the flows `dry_run_workflow` agent # tool (Phase 5b) runs a *draft* graph against so the workflow-builder agent can # self-verify a proposal without any real side effects (no real LLM/tool/HTTP/code). # # Optional: exclusive to the default-ON `flows` feature (#4797). A slim build # without `flows` drops this crate and its `jaq-*` JSON-query stack entirely. tinyflows = { version = "0.5", features = ["mock"], optional = true } # TinyJuice — host-agnostic TokenJuice compression engine. OpenHuman keeps # config/RPC/tool/runtime adapters in `src/openhuman/tokenjuice/` and patches # this dependency to the vendored submodule below. tinyjuice = { version = "0.2.1", default-features = false } # TinyAgents — Rust LLM orchestration framework (LangGraph/LangChain-style): # durable state graphs, agent-loop harness, model/tool registries, REPL + # `.rag` workflow language. openhuman's agent engine + orchestration run on this # crate's primitives via the adapter seam in `src/openhuman/tinyagents/` (issue # #4249): every turn drives through the harness; the workflow phase DAG, team # member runtime, parallel fan-out, and multi-stage delegation run on graphs. # We wire openhuman's own Provider/Tool, not the removed bundled openai client. # The `sqlite` feature is enabled now that openhuman's direct rusqlite pin is # aligned to 0.40, avoiding duplicate `links = "sqlite3"` native bindings. # Durable graph checkpoints still use `SqlRunLedgerCheckpointer` until the # migration re-points those rows to the crate checkpointer. # The `repl` feature (embedded Rhai `.ragsh` session runtime powering the # `rhai_workflows` language-workflow tool, `src/openhuman/rhai_workflows/`) is # NOT enabled here — the default-ON `flows` feature turns it on via # `tinyagents/repl` (#4797), so a slim build without `flows` sheds `rhai`. # The crate itself can never be dropped: 26+ domains consume tinyagents. tinyagents = { version = "2.1", features = ["sqlite"] } # TinyCortex — Rust core for the memory engine (store/chunks/tree/retrieval/ # queue/ingest/score + long tail), vendored as a git submodule and patched # below to `vendor/tinycortex`. OpenHuman's memory subsystem migrates onto this # crate through the adapter seam in `src/openhuman/tinycortex/` (mirroring the # tinyagents seam): engine logic (including provider sync pipelines) in the # crate; RPC, agent tools, sync scheduling/credentials/events, security gating, # and the global singleton stay host-side. rusqlite/git2 are # aligned to the host pins (=0.40 / 0.21) so one bundled SQLite + one libgit2 # link. The submodule intentionally tracks reviewed upstream main commits; # keep this semver requirement compatible with the vendored crate version. tinycortex = { version = "0.1", features = ["git-diff", "persona", "sync"] } tinychannels = { version = "0.1", features = ["relay-websocket"] } serde = { version = "1", features = ["derive"] } serde_json = "1" serde_repr = "0.1" serde_yaml = "0.9" # dhat — heap profiler for the offline `library-profile` benchmark binary only. # Default-OFF, dev-only: pulled in solely by the `rss-bench-dhat` feature so it # never enters the shipped desktop/library build (same posture as `rss-bench`). dhat = { version = "0.3", optional = true } # (Removed `html2md` dep. dhat-rs profiling on real Gmail inboxes # showed `html2md::walk` and `html2md::tables::handle` allocating # ~894 MB peak heap on a 10 KB HTML input from Otter.ai-style emails # (deeply-nested table-as-layout HTML). Cause: recursive walker holding # per-frame Vec state across nesting layers + 5 sequential # `regex::replace_all` passes in `clean_markdown` each producing a # fresh full-size String. We now use a linear-time tag-and-entity # stripper (`fast_html_to_text` in # providers/gmail/post_process.rs) and prefer the email's # `text/plain` MIME part when available.) # TLS: rustls only in the base declaration, so Linux/macOS — including the # headless embedding target (#5046) — link a single TLS stack + cert set # (Mozilla webpki-roots). Windows re-adds `native-tls` via the # `[target.'cfg(windows)'.dependencies]` block below (Cargo unions features # per target), because `src/openhuman/tls/mod.rs` deliberately routes the # Windows client through the SChannel/OS cert store for corporate MITM + # AV root CAs. So the two TLS backends coexist only on Windows, never on # the RAM-sensitive platforms. reqwest = { version = "0.12", default-features = false, features = ["json", "blocking", "rustls-tls", "stream", "http2", "multipart", "socks"] } # Already in-tree via reqwest/hyper; named directly so `IntegrationClient::get_bytes` # can return `bytes::Bytes` without a copy. bytes = "1" tokio = { version = "1", features = ["full"] } once_cell = "1.19" parking_lot = "0.12" log = "0.4" libc = "0.2" nu-ansi-term = "0.46" env_logger = "0.11" base64 = "0.22" aes-gcm = "0.10" argon2 = "0.5" rand = "0.10" dirs = "5" sha2 = "0.10" # Git-backed change ledger for the memory_diff module: snapshots are commits, # checkpoints are tags, read markers are refs, diffs are git tree diffs. # Vendored libgit2 (no system git dependency on end-user machines). git2 = { version = "0.21", default-features = false, features = ["vendored-libgit2"] } hmac = "0.12" # Archive extraction for the Node.js runtime bootstrap. Unix Node # distributions ship as .tar.xz, Windows as .zip. `xz2` with `static` # bundles liblzma so we don't need it as a system dependency. tar = "0.4" xz2 = { version = "0.1", features = ["static"] } zip = { version = "2", default-features = false, features = ["deflate"] } # gzip decoder for the Piper tar.gz binary releases on macOS / Linux. Already # pulled in transitively by zip's `deflate` feature; declared directly so # the installer module can `use flate2::read::GzDecoder`. flate2 = "1" # Real timeout for `node --version` probes in the runtime resolver. Guards # against a broken shim on PATH hanging the bootstrap forever. wait-timeout = "0.2" uuid = { version = "1", features = ["v4"] } anyhow = "1.0" async-trait = "0.1" chacha20poly1305 = "0.10" # Wipe master keys / decrypted secret buffers from memory on drop (audit C9). # Already present transitively (resolved to 1.8.x via the *-dalek / cipher # crates); declared directly so the keyring module can `use zeroize::Zeroizing`. zeroize = "1" x25519-dalek = { version = "2", features = ["static_secrets"] } hkdf = "0.12" hex = "0.4" tokio-util = { version = "0.7", features = ["rt", "io"] } # tokio-tungstenite is declared per-target below so the TLS backend # (native-tls on Windows, rustls on macOS / Linux) matches the reqwest # backend selected at each TLS call site. futures = "0.3" rusqlite = { version = "=0.40.0", features = ["bundled"] } chrono = { version = "0.4", features = ["serde"] } iana-time-zone = "0.1" cron = "0.12" futures-util = "0.3" directories = "6" toml = "1.0" schemars = "1.2" tracing = { version = "0.1", default-features = false } tracing-log = "0.2" tracing-subscriber = { version = "0.3", default-features = false, features = ["fmt", "ansi", "env-filter"] } tracing-appender = "0.2" urlencoding = "2.1" motosan-ai-oauth = { version = "0.2", features = ["codex"] } thiserror = "2.0" ring = "0.17" chrono-tz = "0.10" dotenvy = "0.15" regex = "1.10" # Multi-pattern fixed-string DFA matcher used by `routing::quality` for # refusal/empty-noise detection on local-model responses. Already in the # dep graph transitively via `regex` (which uses it for literal # optimization); declared directly here so `openhuman` owns the # version pin and the import isn't an unstable transitive surface. aho-corasick = "1.1" walkdir = "2" glob = "0.3" hostname = "0.4.2" rustls = { version = "0.23", default-features = false, features = ["ring"] } sysinfo = { version = "0.33", default-features = false, features = ["system"] } keyring = { version = "3", features = ["apple-native", "windows-native", "linux-native"] } clap = { version = "4.5", features = ["derive"] } lettre = { version = "0.11.22", default-features = false, features = ["builder", "smtp-transport", "rustls-tls"], optional = true } # HTTP + Socket.IO server transport — the `/rpc` JSON-RPC endpoint, `/v1` # OpenAI-compat router, agentbox/http_host sub-servers, and the Socket.IO # live-event bridge. Exclusive to the default-ON `http-server` feature (#5048): # a slim/embedded build without it (`--no-default-features`) sheds `axum` + # `socketioxide` and never binds a listener — the core still runs background # services and answers over the CLI/native dispatch surface. See the # `http-server` feature note below and `src/core/http_server_status.rs`. axum = { version = "0.8", default-features = false, features = ["http1", "json", "tokio", "query", "ws", "macros"], optional = true } sentry = { version = "0.47.0", default-features = false, optional = true, features = ["backtrace", "contexts", "panic", "tracing", "debug-images", "httpdate"] } tokio-stream = { version = "0.1.18", default-features = false, features = ["sync"] } url = "2" socketioxide = { version = "0.15", features = ["extensions"], optional = true } whisper-rs = { version = "0.16", optional = true } tempfile = "3" cpal = { version = "0.15", optional = true } hound = { version = "3.5", optional = true } enigo = "0.3" arboard = "3" rdev = "0.5" fs2 = "0.4" # Cross-platform battery probe for the scheduler gate. Maintained fork of # the abandoned `battery` crate; same `use battery::*;` API surface. Used # only by `openhuman::scheduler_gate::signals` to decide when to throttle # background LLM work on laptops. starship-battery = "0.10" ethers-core = { version = "2.0.14", default-features = false } ethers-signers = { version = "2.0.14", default-features = false } # Multi-chain wallet signing. # - bitcoin: P2WPKH PSBT build/sign/broadcast (includes secp256k1). # - ed25519-dalek: Solana transaction signing. # - bs58: Solana base58 addresses + Tron base58check addresses. bitcoin = { version = "0.32", default-features = false, features = ["std", "secp-recovery", "rand-std"], optional = true } ed25519-dalek = { version = "2", default-features = false, features = ["std", "rand_core"] } bs58 = { version = "0.5", default-features = false, features = ["std", "check"] } # Shared BIP-39 mnemonic → seed for non-EVM chains (BTC P2WPKH derivation, # Tron secp256k1 derivation, Solana ed25519 SLIP-0010 derivation). Same crate # ethers-signers uses internally, exposed as a direct dep so we can derive # off the recovery phrase without going through the EVM signer wrapper. coins-bip39 = "0.8" # Solana off-curve check for ATA derivation (find_program_address). curve25519-dalek = { version = "4", default-features = false, features = ["alloc"], optional = true } fantoccini = { version = "0.22.0", optional = true, default-features = false, features = ["rustls-tls"] } pdf-extract = { version = "0.10", optional = true } # The WhatsApp Web provider (and its `whatsapp-rust` / `wacore` / `serde-big-array` # stack) now lives in the tinychannels crate; the `whatsapp-web` feature forwards # to `tinychannels/whatsapp-web`. ppt-rs = { version = "0.2.14", optional = true } # Terminal chat UI (`openhuman tui` / `chat`). Exclusive to the default-ON # `tui` feature (see `[features]` below): a slim / headless build without `tui` # drops both `ratatui` and `crossterm`. Kept in lockstep — ratatui 0.30 # re-exports crossterm 0.29, so declaring crossterm directly at the same major # unifies to a single crossterm in the dep graph. Only compiled into # `src/tui/` behind `#[cfg(feature = "tui")]`. ratatui = { version = "0.30", optional = true } crossterm = { version = "0.29", optional = true } # Terminal column-width measurement for the `tui` chat renderer # (`src/tui/render.rs`); only compiled behind `#[cfg(feature = "tui")]`. unicode-width = { version = "0.2", optional = true } # Native-Rust `.docx` writer for the `generate_document` tool (GH #4847). # Pure Rust (no subprocess / managed runtime), MIT-licensed, actively # maintained (2.8M downloads, last release 0.4.20 — Apr 2026). Mirrors the # `ppt-rs` presentation engine: synthesise bytes in-process, hand them to # the byte-agnostic artifact pipeline. `default-features` keeps the crate's # image support (unused here, but avoids a bespoke feature list drifting). docx-rs = { version = "0.4.20", optional = true } [target.'cfg(windows)'.dependencies] # Windows: tokio-tungstenite uses native-tls (schannel) so wss:// # connections honor the Windows cert store, including corporate CAs # installed by AV / TLS-inspection proxies. See run-dev-win.sh notes. tokio-tungstenite = { version = "0.24", default-features = false, features = ["connect", "handshake", "native-tls"] } # Windows re-adds reqwest's native-tls backend (dropped from the base decl in # `[dependencies]`) so `tls::tls_client_builder()` can call `.use_native_tls()` # and reach the SChannel/OS cert store — same rationale as tokio-tungstenite # above. Cargo unions these features with the base rustls decl, so on Windows # reqwest carries both backends; Linux/macOS keep rustls only. reqwest = { version = "0.12", default-features = false, features = ["native-tls"] } # AppContainer / process-jail backend in `openhuman::cwd_jail`. # Feature list mirrors the Win32 surface used by cwd_jail/windows.rs: # AppContainer profile APIs, ACL editing, STARTUPINFOEXW process spawn, # and the GENERIC_* file access masks. windows-sys = { version = "0.61", features = [ "Win32_Foundation", "Win32_Security", "Win32_Security_Authorization", "Win32_Security_Isolation", "Win32_Storage_FileSystem", "Win32_System_Memory", "Win32_System_Threading", ] } [target.'cfg(not(windows))'.dependencies] # macOS / Linux: keep rustls + Mozilla webpki-roots — the historical # default. Avoids pulling OpenSSL as a runtime dep on Linux. tokio-tungstenite = { version = "0.24", default-features = false, features = ["connect", "handshake", "rustls-tls-webpki-roots"] } [target.'cfg(target_os = "macos")'.dependencies] whisper-rs = { version = "0.16", features = ["metal"], optional = true } # Contacts framework bindings for address book seeding. objc2 = "0.6" objc2-foundation = { version = "0.3", features = ["NSArray", "NSError", "NSObject", "NSString", "NSPredicate"] } objc2-contacts = { version = "0.3.2", features = ["CNContact", "CNContactFetchRequest", "CNContactStore", "CNLabeledValue", "CNPhoneNumber"] } block2 = "0.6" [target.'cfg(target_os = "linux")'.dependencies] landlock = { version = "0.4", optional = true } rppal = { version = "0.22", optional = true } [dev-dependencies] # Enable sentry's TestTransport for runtime smoke of the observability # before_send filter (see tests/observability_smoke.rs). `default-features # = false` here is load-bearing — sentry's default feature set pulls in # actix-web / actix-http / actix-server / sentry-actix and ~13 transitive # crates we never use (and that bloat the dev Cargo.lock noticeably). # TestTransport only needs the `test` feature. sentry = { version = "0.47.0", default-features = false, features = ["test"] } # axum is optional in `[dependencies]` (exclusive to the default-ON # `http-server` feature, #5048), but ~17 `#[cfg(test)]` modules stand up # in-process axum mock servers / call `build_core_http_router` regardless of # the feature set under test. Declaring a plain (non-optional) dev-dep keeps # those tests compiling in ALL test builds without per-file `#[cfg]` — mirrors # the `sentry` dual-declaration above. The prod fns those tests exercise are # still gated, so the *tests* naming them carry `#[cfg(feature = "http-server")]`. axum = { version = "0.8", default-features = false, features = ["http1", "json", "tokio", "query", "ws", "macros"] } # `tower` was a plain runtime dep only for its re-exports in the axum server # path; with `http-server` optional it is test-only (tower::ServiceExt::oneshot # drives the mock routers), so it lives here as a dev-dep now. tower = { version = "0.5", default-features = false } # Mock HTTP server for provider E2E tests (inference_provider_e2e). wiremock = "0.6" # Used in json_rpc_e2e to backdate mtime on stale lock files. filetime = "0.2" # `test-util` enables tokio's paused virtual clock (`start_paused`, # `time::advance`) so the #4270 inference-heartbeat tests assert the periodic # beat without real-time waits. Test-only — the runtime feature set in # `[dependencies]` (`full`) intentionally excludes it. tokio = { version = "1", features = ["test-util"] } # Property-based testing for the adversarial-input surfaces (command classifier, # encryption round-trip) — plan.md §6.3. Version already resolved in Cargo.lock. proptest = "1" [features] default = ["tokenjuice-treesitter", "inference", "voice", "web3", "media", "documents", "meet", "skills", "flows", "mcp", "crash-reporting", "http-server", "channels", "tui", "medulla"] # HTTP + Socket.IO server transport (#5048): the `/rpc` JSON-RPC endpoint and # its auth middleware/CORS layer (`core::jsonrpc`, `core::auth`), the `/v1` # OpenAI-compatible router (`inference::http`), the ad-hoc static-dir file # server (`openhuman::http_host`), the AgentBox `/run` HTTP surface # (`agentbox::http`), the WebSocket dictation stream # (`inference::voice::streaming`), the `openhuman text-input run` dev server, # the MCP Streamable-HTTP transport (`mcp_server::http`, additionally gated by # `mcp`), and the Socket.IO live-event bridge (`core::socketio`). Default-ON — # the desktop shell REQUIRES it (see the `HTTP_SERVER_COMPILED_IN` compile # assert in `app/src-tauri/src/lib.rs`). Slim / headless-embedding builds opt # out via `--no-default-features --features ""`, which drops the exclusive `axum` + `socketioxide` deps; the # core then runs background services without binding a listener (`serve()` # returns early) and is driven over the CLI / native dispatch surface instead. # # TYPE CARVE-OUT (see AGENTS.md): `core::socketio`'s inert event payload types # (`WebChannelEvent`, `TurnUsagePayload`, `SubagentUsagePayload`, # `SubagentProgressDetail`) stay compiled in BOTH builds — ~10 always-on # domains construct them — so `pub mod socketio;` is UNGATED and only the # socketioxide/axum-touching bodies are gated. Likewise `inference::http::types` # and `EXTERNAL_OPENAI_COMPAT_PROVIDER` stay compiled for `core::auth`. http-server = ["dep:axum", "dep:socketioxide"] # AST-aware code compression (tree-sitter Rust/TS/Python grammars; C build). # On by default; disable to fall back to the brace-depth heuristic. tokenjuice-treesitter = [ "tinyjuice/tinyjuice-treesitter", ] # In-process inference engine: the whisper.cpp STT engine # (`inference::local::service::whisper_engine`) plus the `cpal` audio-device # probe shared by voice capture and the accessibility microphone-permission # check. Default-ON. Slim / headless builds opt out via # `--no-default-features --features ""`, which # drops the exclusive `whisper-rs` (including the macOS `metal` variant and the # `whisper-rs-sys` patch, which go inert once whisper-rs leaves the graph) and # `cpal` dependencies. When off, the whisper facade resolves to # `whisper_engine::stub` — in-process STT returns a disabled error, while the # local-AI service still reaches Ollama / LM Studio over HTTP — and the # microphone probe reports `Unknown`. `voice` requires this gate, so building # `voice` always pulls `inference` in transitively. inference = ["dep:whisper-rs", "dep:cpal"] # Office-document tools: the `generate_presentation` (ppt-rs) and # `generate_document` (docx-rs) agent tools, plus `pdf-extract` for PDF text # extraction during multimodal file ingest. Default-ON. Slim / headless builds # opt out via `--no-default-features --features ""`, which drops all three crates. Leaf gate (no stub facade): when # off, the two tools are absent from the tool list rather than degraded to an # error, and PDF ingest degrades the file to a reference instead of extracted # text (`agent::multimodal::extract_pdf_text`). documents = ["dep:pdf-extract", "dep:ppt-rs", "dep:docx-rs"] # Voice + audio_toolkit domains: STT/TTS providers, the standalone dictation # server, always-on listening, and podcast audio generation/email delivery. # Default-ON — the desktop app always ships with voice. Slim / headless builds # opt out via `--no-default-features --features ""`, # which also drops the exclusive `hound` (WAV I/O) + `lettre` (podcast email) # dependencies. Composes with the runtime `DomainSet::voice` flag (#4796): the # feature narrows the compile-time surface, `DomainSet` gates it at runtime. # Requires `inference` (the whisper engine + the cpal capture stack), so # enabling `voice` turns `inference` on transitively. voice = ["inference", "dep:hound", "dep:lettre"] # Web3 domains: openhuman::wallet + openhuman::web3 + openhuman::x402 — the # crypto wallet (multi-chain sign/broadcast), the high-level swap/bridge/dapp # surface, and the x402 machine-payment protocol. Default-ON — the desktop app # always ships with the wallet. Slim / headless builds opt out via # `--no-default-features --features ""`, which also # drops the exclusive `bitcoin` (P2WPKH PSBT) + `curve25519-dalek` (Solana # off-curve ATA) dependencies. Composes with the runtime `DomainSet::Web3` flag # (#4796): the feature narrows the compile-time surface, `DomainSet` gates it at # runtime. NOTE: this gate does NOT drop ethers-core / ethers-signers / # coins-bip39 / bs58 / ed25519-dalek / ripemd — those are shared with the # Polymarket tools + tinyplace on-chain payments + orchestration and stay # always-on. When off, tinyplace payments + Polymarket writes degrade to # graceful "wallet disabled" errors via the wallet/web3/x402 stub facades. web3 = ["dep:bitcoin", "dep:curve25519-dalek"] # Media-generation + image domains: the `media_generate_*` agent tools # (image/video via GMI through the backend) and the `openhuman::image` tool # contracts scaffold. Default-ON. Slim builds opt out via # `--no-default-features --features ""`. # Composes with the runtime `DomainSet::media` flag (#4796). # NOTE: this gate sheds no exclusive dependencies — media generation is # backend-proxied (reqwest, shared). It is a surface-only gate (drops the tool # code + module from the compile), not a dependency-shedding one. There are no # controllers / stores / subscribers tagged `Media` (agent tools only), and # `openhuman::image` is currently unwired scaffold (added #2997). media = [] # Flows domains: the `flows::` automation surface (saved tinyflows graphs — # create/run/schedule + the workflow_builder / flow_discovery agents), the # `tinyflows::` adapter seam, and the `rhai_workflows::` language-workflow tool. # Default-ON — the desktop app always ships with Workflows. Slim / headless # builds opt out via `--no-default-features --features ""`, # which drops `tinyflows` + its `jaq-core`/`jaq-std`/`jaq-json` JSON-query stack # and, via `tinyagents/repl`, the `rhai` scripting engine. Composes with the # runtime `DomainSet::flows` flag (#4796): the feature narrows the compile-time # surface, `DomainSet` gates it at runtime. # NOTE: this gate does NOT drop `tinyagents` itself — 26+ domains consume it. # Only its `repl` feature (⇒ `rhai`) is exclusive to flows. flows = ["dep:tinyflows", "tinyagents/repl"] # Meet domains: `meet` (join-URL validation), `meet_agent` (live STT/LLM/TTS # loop over an open call), and `agent_meetings` (backend-delegated Meet bot via # Socket.IO). Default-ON — the desktop app always ships with Meet. Slim / # headless builds opt out via `--no-default-features --features ""`. Composes with the runtime `DomainSet::meet` flag (#4796): the feature # narrows the compile-time surface, `DomainSet` gates it at runtime. # NOTE: unlike `voice`, this gate drops NO dependencies — the Meet domains have # zero exclusive crates. `meet_agent::wav` is a hand-rolled RIFF writer # precisely so Meet never needed `hound` (which `voice` already owns), so the # dependency shed was pre-paid. The gate's value is compile-time surface + # binary size, not the dep tree. # CARVE-OUT: `meet_agent::wav` stays compiled in ALL builds — the always-on # `desktop_companion` STT path depends on it. See `meet_agent/mod.rs`. meet = [] # Skills domains: `openhuman::skills` (metadata/discovery/install), # `openhuman::skill_runtime` (SKILL.md execution + the skill_executor agent), # and `openhuman::skill_registry` (remote catalogs + the skill_setup agent). # Default-ON — the desktop app always ships with skills. Slim / headless builds # opt out via `--no-default-features --features ""`. # Composes with the runtime `DomainSet::skills` flag (#4796): the feature # narrows the compile-time surface, `DomainSet` gates it at runtime. # # The dep list is INTENTIONALLY EMPTY — do not "fix" it. Unlike `voice` # (`hound`/`lettre`), these domains have no exclusive dependencies: every crate # they touch (serde, serde_json, tokio, anyhow, async-trait, …) is shared with # always-on domains, and `runtime_node`/`runtime_python` are used by Agent / # Flows / Memory too. This gate's value is tool-surface + prompt-bloat + # startup cost, NOT binary size. # # NOTE: `openhuman::skills::types` and `::ops_types` stay compiled even when # this feature is OFF — `tools::traits` re-exports `ToolResult`/`ToolContent` # out of `skills::types` and ~236 files consume them, so those inert serde # types are a type carve-out, not part of the gated behaviour. See # `src/openhuman/skills/stub.rs`. skills = [] # MCP domains: `mcp_server` (the `openhuman mcp` stdio/HTTP server exposing our # tool surface), `mcp_registry` (dynamic Smithery installs — SQLite, lifecycle, # `mcp_clients` RPC namespace), `mcp_audit` (write-audit log), and the # static/config-declared server set in `mcp_client`. Default-ON — the desktop # app always ships with MCP. Composes with the runtime `DomainSet::mcp` flag # (#4796): this feature narrows the compile-time surface, `DomainSet` gates it # at runtime. # # INTENTIONALLY EMPTY — do NOT "fix" this by adding `dep:` entries. There is no # MCP SDK in this crate: the whole protocol stack is hand-rolled over tokio # process stdio + reqwest + axum, every one of which is load-bearing for # non-MCP domains. So this gate drops ~20k LOC and ~19 agent tools but ZERO # dependencies. The issue-level DoD line claiming it "sheds the MCP SDK / # transport stack" is superseded by this correction (see AGENTS.md). # # NOTE: `mcp_client::{sanitize, client}` stay ALWAYS compiled — they are # mis-housed shared utilities (the gitbooks docs tool dials `McpHttpClient`; # the orchestrator prompt sanitises *skill* descriptions through # `sanitize::sanitize_for_llm`). The gate follows the real dependency graph, # not the directory name. mcp = [] # Sentry crash/error reporting: the `sentry::init` guard + secret-scrubbing # `before_send` hook (src/main.rs), the sentry-tracing bridge layer # (core::logging), the ~24 `before_send` Event classifiers + the two # `report_*_message` capture paths (core::observability), the session-boundary # scope binding (credentials::sentry_scope), and the `openhuman sentry-test` # CLI probe. Default-ON — the desktop app always ships with crash reporting. # Slim / headless builds opt out via `--no-default-features --features # ""`, which drops the exclusive # `sentry` dependency (and its transitive backtrace/contexts/panic/tracing/ # debug-images/reqwest/rustls stack) from the non-test build. # # TYPE CARVE-OUT (see AGENTS.md "Compile-time domain gates"): the sentry-free # string classifiers (`is_transient_message_failure`, # `is_insufficient_credits_message`, `contains_transient_transport_phrase`, …) # and the `report_*_message` / `sentry_scope::{bind,clear}` signatures stay # compiled in BOTH builds — only the `sentry::`-touching bodies are gated — so # NO stub file is needed and always-on callers need no per-call `#[cfg]`. When # off, `report_error_message`/`report_warning_message` still emit their # `tracing::{error,warn}!` diagnostic, `sentry_tracing_layer()` degrades to a # no-op `Identity` layer, and `openhuman sentry-test` returns a "built without # the crash-reporting feature" error. crash-reporting = ["dep:sentry"] # Tabbed terminal UI: the `openhuman tui` (alias `chat`) CLI subcommand, a # ratatui/crossterm front-end for logs, orchestrator chat, curated configuration, # and account settings. Default-ON for the standalone `openhuman-core` binary, but # INTENTIONALLY NOT forwarded to the desktop shell (the desktop app ships its own # Tauri UI and never needs a terminal one) — see the allowlist entry in # `scripts/ci/check-feature-forwarding.mjs`. Slim / headless builds opt out via # `--no-default-features --features ""`, which drops # the exclusive `ratatui` + `crossterm` dependencies. The crate-root # `src/tui/` module is declared only under `#[cfg(feature = "tui")]`; when off, # the always-compiled CLI dispatcher returns a build-fact "tui feature disabled # at compile time" error for the `"tui" | "chat"` commands. tui = ["dep:ratatui", "dep:crossterm", "dep:unicode-width"] # Medulla integration: the HTTP/SSE client for the Medulla orchestration backend # (`openhuman::medulla::client`) — durable sessions, event streaming, worker # routing + roster, the operator task ledger and its GitHub sources, one-shot # orchestration runs, the public feedback board, and the onboarding history # reward. This is the real Medulla surface; it replaced the `medulla-local` # supervised-child draft, which has been removed. # # Default-ON, but INTENTIONALLY NOT FORWARDED to the Tauri shell (allowlisted in # scripts/lib/feature-forwarding.mjs, alongside `tui`): the desktop app is # OpenHuman's own product and never dials a Medulla backend. The consumer is the # Medulla TUI, which embeds this crate directly. # # Facade + type carve-out, NOT a leaf gate: `pub mod medulla;` is always # compiled, and `medulla::contract` + `medulla::events` stay compiled in BOTH # builds because `src/embed/` names those types in public signatures. Only # `medulla::client` — everything that touches reqwest — is gated. This follows # the rule the `skills` / `mcp_registry` gates established: carve inert types # out and gate behaviour, so the two builds share one type definition and # cannot drift. # # Sheds ZERO exclusive dependencies — do NOT "fix" the empty list. `reqwest`, # `futures`, `serde`, and `tokio` are all load-bearing for other domains; the # gate's value is compile-time surface and RPC/tool reach, not binary size. # Verify before ever claiming otherwise: # cargo tree -i reqwest --no-default-features --features tokenjuice-treesitter medulla = [] # Channels domain: `openhuman::channels` (external-messaging providers — Telegram, # Discord, Slack, Signal, WhatsApp, iMessage, IRC, … — plus the channel runtime, # controllers, host, proactive messaging and inbound dispatch) together with the # `webview_accounts` / `webview_apis` / `webview_notifications` / `whatsapp_data` # webview-bridge domains. Default-ON — the desktop app always ships with # channels. Slim / headless builds opt out via `--no-default-features --features # ""`. Composes with the runtime # `DomainSet::Channels` flag (#4796): this feature narrows the compile-time # surface, `DomainSet` gates it at runtime. # # INTENTIONALLY EMPTY — do NOT "fix" this by adding `dep:` entries. This gate # sheds ZERO dependencies: `tinychannels` stays load-bearing regardless # (`config/schema/channels.rs` re-exports its config types, `event_bus/events.rs` # `DomainEvent` embeds `tinychannels::ChannelInboundEnvelope`, and # `security/pairing.rs` re-exports its pairing helpers), so it is always # compiled. The gate's value is compile-time surface + binary size, not the dep # tree. (`whatsapp-web` refines this gate — see below — forwarding to the # `tinychannels/whatsapp-web` provider feature.) # # NOTE: the in-app web chat (`openhuman::web_chat`, RPC namespace `channel`) is # NOT gated by this feature even though its runtime tag is # `DomainGroup::Channels` — it is core product surface and stays always # compiled (decoupled from `channels/` in #5002). The `channels::{traits, cli}` # carve-outs also stay ungated — `traits` is a 1-line tinychannels re-export and # `cli::CliChannel` is the dep-free local REPL used by the always-on agent # harness interactive loop. See AGENTS.md "channels gate" + `channels/mod.rs`. channels = [] sandbox-landlock = ["dep:landlock"] sandbox-bubblewrap = [] peripheral-rpi = ["dep:rppal"] browser-native = ["dep:fantoccini"] fantoccini = ["browser-native"] landlock = ["sandbox-landlock"] # The WhatsApp Web provider now lives in tinychannels; forward to its feature. # It is a refinement INSIDE the `channels` gate — enabling it pulls in the whole # channels domain (the provider re-exports live under `channels/providers/`). whatsapp-web = ["channels", "tinychannels/whatsapp-web"] # Exposes the destructive `openhuman.test_reset` RPC. Off by default; the E2E # build (app/scripts/e2e-build.sh) flips it on. Shipped binaries never have # this feature so the wipe RPC isn't even registered, let alone reachable. e2e-test-support = [] # Builds the `rss-bench` benchmark binary (#5046). Default-OFF, so it is never # part of the shipped desktop/library build and the feature-forwarding gate # (which only inspects the `default` list) never requires forwarding it. rss-bench = [] # Adds dhat heap profiling on top of `rss-bench` for the `library-profile` # binary. Default-OFF, dev-only: installs dhat's global allocator, which # perturbs RSS/timing numbers, so it is a separate opt-in feature rather than # folded into `rss-bench`. Never forwarded to the shipped build. rss-bench-dhat = ["rss-bench", "dep:dhat"] [lints.rust] unexpected_cfgs = { level = "warn", check-cfg = ['cfg(coverage)'] } # These project-wide shape/documentation lints describe intentional public APIs # and long-standing module docs. Keep them explicitly baselined so `-D warnings` # can make every other Clippy and rustc diagnostic a hard failure. [lints.clippy] borrowed_box = "allow" doc_overindented_list_items = "allow" field_reassign_with_default = "allow" large_enum_variant = "allow" result_large_err = "allow" should_implement_trait = "allow" too_many_arguments = "allow" while_let_loop = "allow" # Fix whisper-rs-sys CRT mismatch on Windows MSVC (LNK2038). # Upstream cmake build defaults to /MD but Rust uses /MT. # This fork adds config.static_crt(true) to the build script. # See: https://github.com/tinyhumansai/openhuman/issues/273 [patch.crates-io] whisper-rs-sys = { git = "https://github.com/tinyhumansai/whisper-rs-sys.git", branch = "main" } # Upstream 0.2.1 enables reqwest's default native-tls backend even though it # also requests rustls. Patch the official release locally so Linux/macOS do # not inherit OpenSSL; the only source delta disables reqwest defaults. # Windows still enables native-tls through the target-specific dependency # above. Remove this patch after upstream publishes the same manifest fix. motosan-ai-oauth = { path = "vendor/motosan-ai-oauth" } # TinyAgents is vendored as a git submodule (pinned at the released tag) so # migration work can change the SDK source in-tree, test it against OpenHuman # immediately, and PR the diff upstream from the submodule. Keep the submodule # version in lockstep with the `tinyagents` requirement above. After cloning: # `git submodule update --init vendor/tinyagents` (worktrees included). tinyagents = { path = "vendor/tinyagents" } # TinyFlows, TinyCortex, TinyJuice, TinyChannels, and TinyPlace are vendored beside # TinyAgents so integration work can test crate changes against OpenHuman before # publishing. tinyflows = { path = "vendor/tinyflows" } tinycortex = { path = "vendor/tinycortex" } tinyjuice = { path = "vendor/tinyjuice" } tinychannels = { path = "vendor/tinychannels" } tinyplace = { path = "vendor/tinyplace/sdk/rust" } # Emit just enough DWARF in release builds for Sentry to symbolicate Rust # panics + render surrounding source lines. `line-tables-only` keeps the # binary small (only file+line tables, no full type info) while still # letting `sentry-cli debug-files upload --include-sources` produce a # usable `.src.zip`. `split-debuginfo = "packed"` writes the debug data # into a separate `.dSYM` bundle on macOS so the shipped executable # itself stays slim. [profile.release] debug = "line-tables-only" split-debuginfo = "packed" # Fast CI builds: trade runtime perf for compile speed [profile.ci] inherits = "release" opt-level = 1 codegen-units = 16 lto = false incremental = false strip = true debug = false # Faster local + CI iteration (#3877): compile third-party dependencies in the # dev/test profiles WITHOUT debuginfo. The dependency graph here is large (a # local checkout showed root `target/` ~12G and Tauri `target/` ~4.4G), and # DWARF generation + linking for every dependency is a dominant, repeated cost # across `cargo build`, `cargo test`, `cargo clippy`, and `cargo llvm-cov`. # # Scope is intentionally narrow and low-risk: # * `package."*"` targets dependencies only — our own crates keep full # debuginfo, so panics/backtraces in OpenHuman code still resolve to # file:line and a debugger can still step through our code. # * Only the unoptimised `dev`/`test` profiles change. `release` and `ci` # (which already set `debug = false` / `line-tables-only`) are untouched. # * No artifact paths, features, or runtime behaviour change — this only # reduces how much DWARF is emitted for dependencies, which also shrinks # `target/` substantially. [profile.dev.package."*"] debug = false