8000 openhuman/Cargo.toml at main · dominikake/openhuman · GitHub
[go: up one dir, main page]

Skip to content

Latest commit

 

History

History
1344 lines (1303 loc) · 77.3 KB

Cargo.toml

File metadata and controls

1344 lines (1303 loc) · 77.3 KB
[package]
name = "openhuman"
version = "0.63.17"
edition = "2021"
description = "OpenHuman core business logic and RPC server"
# The crate ships a verbatim GPLv3 `LICENSE` file but carried no `license` key,
# which left the grant ambiguous to every tool that reads metadata rather than
# the file (cargo-deny, crates.io, SBOM generators). Declared explicitly as
# `only` — not `or-later` — to match `medulla-public` and the `GPL-3.0-only`
# first-party crates in the closure (`tinyagents`).
license = "GPL-3.0-only"
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"
# `cargo machete` reports a dependency as unused when no `use` names it. These
# two have no `use` and are still load-bearing, so they are suppressed here
# rather than deleted — an unsuppressed false positive is how a real finding
# gets ignored next time.
#
# `tinymemory` (the facade) and `tinymemory-tinycortex` (the TinyCortex
# adapter) exist for DRIVER ADMISSION: the memory subsystem resolves its
# engine through `tinymemory`'s driver registry, and the adapter is what makes
# TinyCortex admissible as that engine. Both must stay linked so a second host
# embedding the `flows` kernel profile can still bind a memory engine — see
# the 2026-08-10 entry in `scripts/kernel-floor.limits`, which ratchets them in
# deliberately. Dropping either would compile clean and fail at runtime.
#
# `tinymemory-api` and `tinymemory-core` are NOT listed: they are named
# directly by `src/openhuman/memory/`, so machete is already satisfied.
[package.metadata.cargo-machete]
ignored = ["tinymemory", "tinymemory-tinycortex"]
[[bin]]
name = "openhuman-core"
path = "src/main.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", "bin-tools"]
# 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"]
# ── Integration tests that need a PRODUCT gate ──────────────────────────────
#
# `[features] default` is the contributor set and no longer turns on `voice`,
# `web3`, `crash-reporting` or `inference`. These four `tests/` targets name
# symbols that only exist behind those gates, so without a `required-features`
# line a bare `cargo test` fails to COMPILE — not skip, fail — and the failure
# is in a file the contributor did not touch.
#
# `required-features` makes cargo skip the target instead, which is the honest
# outcome: the test exercises a domain that build does not contain. The CI
# product lanes pass `--features "$(scripts/ci/product-features.sh)"`, so every
# one of these still runs there, against the code that ships.
#
# Autodiscovery stays on for the other ~59 `tests/*.rs` targets; declaring a
# target explicitly only opts THAT file out of it.
#
# This replaces the per-symbol `#[cfg]` cleanup tracked in #5021 for these four
# files. #5021 is still the right fix for symbols named in the middle of an
# otherwise gate-free target — required-features is the blunt instrument, and
# it costs the whole target when the gate is off.
[[test]]
name = "observability_smoke"
path = "tests/observability_smoke.rs"
# The `is_*_event` Sentry filters are all `#[cfg(feature = "crash-reporting")]`.
required-features = ["crash-reporting"]
[[test]]
name = "memory_artifacts_e2e"
path = "tests/memory_artifacts_e2e.rs"
# Opens the wiki ledger with `tinycortex::git2::Repository::open` and asserts on
# `content::wiki_git` artifacts — both of which exist only behind this gate.
required-features = ["memory-git"]
[[test]]
name = "x402_twit_sh_live"
path = "tests/x402_twit_sh_live.rs"
# `x402::tools::X402RequestTool` — the x402 domain is part of the web3 family.
required-features = ["web3"]
[[test]]
name = "json_rpc_e2e"
path = "tests/json_rpc_e2e.rs"
# `voice::reply_speech::{test_seam, TEST_SEAM_ENV}` — the reply-speech seam
# only exists in the real voice module, not the stub.
required-features = ["voice"]
[[test]]
name = "raw_coverage_all"
path = "tests/raw_coverage_all.rs"
# The merged raw-coverage target spans ~76 former files, so it reaches the
# widest surface of any single target: `lettre` (pulled in through the voice
# gate's `tinychannels/email`) and the local inference download service.
required-features = ["voice", "inference"]
[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", default-features = false }
# 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.8", features = ["mock"], optional = true }
# 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/agent/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 8BD0 .
# `multimodal` is not optional here: `agent::multimodal` is kernel surface —
# web chat and the agent harness both resolve attachment markers on every turn
# — so the gate is on for every OpenHuman build. It costs the dependency graph
# nothing: `base64`, `flate2` and `sha2` are all already resolved in the kernel
# profile, so turning it on moves neither the package count nor the native
# build count that `scripts/check-kernel-floor.sh` ratchets.
tinyagents = { version = "2.1", features = ["sqlite", "multimodal"] }
# 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 is aligned to the host pin
# (=0.40) so one bundled SQLite links. The submodule intentionally tracks
# reviewed upstream main commits; keep this semver requirement compatible with
# the vendored crate version.
# `git-diff` and `wiki-git` are NOT here: they are pulled in by the
# `memory-git` gate below, which is where the git2/libgit2-sys/libz-sys cohort
# enters the graph. This crate holds no `git2` pin of its own to align — the
# gate turns tinycortex's on, and tinycortex is the sole libgit2 link in the
# graph. Everything else tinycortex needs is unconditional.
tinycortex = { version = "0.1", features = [
"obsidian",
"persona",
"sync",
] }
# The memory *contract* — value types, the thirteen capability families, the
# `MemoryProvider` driver trait, and the null reference driver. A direct path
# dependency rather than a re-export, because `tinycortex::memory` aliases back
# only `{error, traits, types}`; `capabilities`, `provider`, `null`, `health`,
# `recall`, and `version` are reachable only through the api crate itself.
# Deliberately dependency-light (no rusqlite/git2/reqwest/regex/async runtime)
# so a third-party driver can compile against the contract without pulling in
# the embedded engine. No `[patch.crates-io]` entry is needed: cargo unifies
# this with the `path = "api"` dependency the engine crate already declares.
tinycortex-api = { path = "vendor/tinycortex/api" }
# tinymemory — the engine-neutral memory layer
# (https://github.com/tinyhumansai/tinymemory). Owns the parts of the memory
# subsystem that are true for *any* engine: the driver-admission rules
# (`tinymemory::registry`) and the three mandatory capability families composed
# over the `Memory` storage trait (`tinymemory::mandatory`). TinyCortex stays
# the engine; this is the layer a second engine would enter through.
#
# 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, and for the same reason
# `app/src-tauri/Cargo.toml` needs no `../../` twin — an unpublished path
# dependency resolves transitively through this manifest.
#
# `tinymemory-tinycortex` is the seam between TinyCortex's contract types and
# TinyMemory's. It names `tinycortex` by version requirement, so the
# `[patch.crates-io]` entry below unifies it onto *this* checkout's engine
# rather than the one pinned inside the tinymemory submodule.
#
# After cloning: `git submodule update --init --recursive vendor/tinymemory`.
# tinyruntime — the runtime router
# (https://github.com/tinyhumansai/tinyruntime). Only the *contract* crate is
# taken here, never the router itself: the router ships as a loadable TinyBus
# module, and a host that also compiled it would carry the download pipeline, the
# worker pool, and their dependency trees for nothing.
#
# `tinyruntime-bus` is deliberately dependency-light — `serde` and `serde_json`
# and nothing else — which is what makes naming the payload types cost this
# manifest almost nothing. The module's own CI asserts it stays that way.
#
# After cloning: `git submodule update --init --recursive vendor/tinyruntime`.
tinyruntime-bus = { path = "vendor/tinyruntime/crates/tinyruntime-bus" }
tinymemory = { path = "vendor/tinymemory/crates/tinymemory" }
tinymemory-api = { path = "vendor/tinymemory/crates/tinymemory-api" }
tinymemory-tinycortex = { path = "vendor/tinymemory/crates/tinymemory-tinycortex" }
# `tinymemory-core` is the *substance* of the memory subsystem, extracted out of
# `src/openhuman/memory/` — the SQLite/vector store, the markdown summary tree,
# the provider sync pipelines, ingestion, recall/query/search, the ingest queue,
# conversations, people, goals and the tool-memory rules.
#
# What deliberately stayed behind in `src/openhuman/memory/` is the *host layer*
# per the tinymemory README split: the RPC surface (`schemas/`, `read_rpc/`),
# agent tools (`tools/`), the security/taint guard (`guard/`), the driver
# binding (`driver/`), the memory agent, and the config mapping. Those reach
# into this crate; this crate never names an OpenHuman type. Everything it needs
# from the host arrives through the seam traits in `tinymemory_api::host`, whose
# implementations live in `src/openhuman/memory/host.rs`.
#
# The `schemars` feature is enabled because the memory config *section* structs
# (`MemoryConfig`, `MemoryTreeConfig`, …) now live in `tinymemory_api::host` and
# are still fields of OpenHuman's `Config`, which derives `JsonSchema`.
tinymemory-core = { path = "vendor/tinymemory/crates/tinymemory-core" }
# tinymcp — the Model Context Protocol client, extracted out of this tree
# (https://github.com/tinyhumansai/tinymcp). Owns both transports, the static
# config-declared server set, the dynamic registry with its store, supervisor
# and OAuth, and the write-audit log. What stays here is the host half: the RPC
# surface, the agent-facing tools, and the prompt-injection scan over remote
# tool definitions, which is host policy.
#
# `tinymcp-bus` is the wire contract — payload types and member names, with no
# transport and no runtime. The `schemars` feature is on because this crate
# generates a settings schema for the desktop application from those types
# rather than from a hand-kept copy.
#
# The path dependency on `tinymcp` itself is still the step-one arrangement. The
# registry entry step two calls for now exists — `src/openhuman/modules/registry.rs`
# pins the v0.3.1 release — but the host still calls the library directly, because
# `tinymcp-bus` v0.3.1 does not yet publish everything this host reaches for:
# `OAuthComplete`, a member returning the already-exported `ConnectedServerOverview`,
# the boot-connect and reconnect-supervisor passes, the `ServerDetail` /
# `AuthDetection` / `AuthKind` reply types, the registry curation helpers, an error
# anchor for the `McpServerNeedsAuth` classifier coupling test, and
# `render_tool_result` / `redact_endpoint` for the ungated `gitbooks` tool. It also
# needs a per-`data_dir` object seam of the shape `modules::memory` already uses,
# since `mcp::host` keys one store per workspace and a module gets one `data_dir` at
# load. Those are upstream work in tinyhumansai/tinymcp.
#
# Correcting what this comment used to promise: dropping the path dependency does
# NOT take reqwest/rusqlite with it. Measured in the kernel profile, `rusqlite` has
# six parents and `reqwest` ten, so `scripts/dep-sim.py --cut tinymcp` projects the
# entire shed at -1 package / -1 name / 0 native builds — the `tinymcp` package and
# nothing beneath it. The boundary buys compilation isolation, not a dependency shed.
#
# After cloning: `git submodule update --init vendor/tinymcp`.
# `default-features = false` drops the TinyBus adapter: this build calls the
# library directly and has no use for a bus inside it.
tinymcp = { path = "vendor/tinymcp/crates/tinymcp", default-features = false, features = [
"rustls-tls",
] }
tinymcp-bus = { path = "vendor/tinymcp/crates/tinymcp-bus", features = ["schemars"] }
tinychannels = { version = "0.1", features = ["relay-websocket"] }
# tinybus — the message bus. Owns what `src/core/event_bus/` used to: the typed
# pub/sub surface (`EventBus`, `EventHandler`, `SubscriptionHandle`), the
# in-process zero-serialization request registry (`NativeRegistry`), and peer
# version negotiation. Vendored as a git submodule beside the other tiny*
# crates and consumed by path.
#
# `DomainEvent` stays here, in `src/core/events.rs`: the catalog is OpenHuman's
# own vocabulary and a generic bus crate must not know it. tinybus is generic
# over the event type and `DomainEvent` implements `tinybus::Event`.
#
# After cloning: `git submodule update --init vendor/tinybus`.
# `uds` is on so the kernel can join a broker that out-of-process integrations
# are already attached to (`core::bus::init_over_socket`). `cli` is not: the
# `tinybus` binary is a developer tool, not something the kernel links.
#
# The dynamic module loader is NOT enabled here. It arrives through this
# crate's own default-ON `modules` feature, which forwards `tinybus/modules`.
# Enabling it unconditionally would put a `dlopen` loader in the kernel
# profile — `tinybus` is always-on surface, so `--no-default-features
# --features flows` would carry `ureq` and the archive stack for a host that
# never loads a module. The kernel-floor ratchet catches exactly that, and did.
tinybus = { path = "vendor/tinybus/crates/tinybus", default-features = false, features = ["macros", "uds"] }
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 = { version = "0.11", optional = true }
base64 = "0.22"
aes-gcm = "0.10"
argon2 = "0.5"
rand = "0.10"
dirs = "5"
sha2 = "0.10"
# NO `git2` HERE, DELIBERATELY — do not add it back. Every use of libgit2 in
# the memory stack lives in tinycortex: the diff ledger (`memory::diff`), the
# wiki mirror (`memory::store::content::wiki_git`), and the persona git-history
# reader. This crate holds the RPC surface, the agent tool and the gate around
# them, and never touches a repository itself, so a direct dependency here was
# a declaration with no `use` behind it. Re-declaring it costs nothing in
# crates (the `memory-git` gate pulls tinycortex's copy either way) but invites
# a second major pin, and `git2` sets `links = "git2"` — two majors in one
# graph is a hard cargo error, not a warning. Test code that must inspect a
# ledger goes through `tinycortex::git2`.
hmac = "0.12"
# Archive handling for the Piper voice installer and the document tools. The
# Node.js and Python toolchain archives are no longer unpacked here — the
# `tinyruntime` module owns that — which is what let `xz2` and its static
# liblzma C build leave this manifest entirely.
tar = "0.4"
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 around a blocking child wait, for the Claude Code auth probe.
# Guards against a broken binary on PATH hanging the caller 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.2", 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 = { version = "0.2", optional = true }
tracing-subscriber = { version = "0.3", default-features = false, features = ["fmt", "ansi", "env-filter"] }
tracing-appender = { version = "0.2", optional = true }
urlencoding = "2.1"
motosan-ai-oauth = { version = "0.2", features = ["codex"] }
thiserror = "2.0"
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"], optional = true }
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 }
tempfile = "3"
cpal = { version = "0.15", optional = true }
enigo = { version = "0.3", optional = true }
arboard = { version = "3", optional = true }
rdev = { version = "0.5", optional = true }
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 = { version = "0.10", optional = true }
# Multi-chain wallet signing.
# - bitcoin: P2WPKH PSBT build/sign/broadcast (includes secp256k1).
# - ed25519-dalek: Solana transaction signing.
# - bs58: Solana base58 addresses + Tron base58check addresses.
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 = { version = "0.8", optional = true }
# 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"] }
# 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`.
# 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 }
# TinyDocs — the document wire contract, and nothing else.
#
# `tinydocs-bus` is the whole dependency: the spec types, their size limits,
# the validation rules, the PNG/JPEG header reader, the error vocabulary and
# the member names. It is `serde` + `thiserror` and nothing else — no writer,
# no `tinybus`, no runtime. Synthesis happens in the `tinydocs` TinyBus module
# (`src/openhuman/modules/`), so this build carries the shape of a document
# without carrying the code that produces one, which is why `docx-rs`,
# `ppt-rs` and `pdf-extract` are absent from the graph entirely rather than
# merely gated.
#
# Sharing the contract rather than re-declaring it is the point. The specs are
# what an LLM is shown as a JSON tool schema and what the module validates
# against; two definitions of that would drift, and the drift would be a tool
# description promising limits the module does not enforce. This crate carried
# a verbatim copy of the contract for exactly that reason and paid exactly that
# risk — `src/openhuman/tools/impl/document/format/` was 1,873 lines that
# differed from `crates/tinydocs-bus/src/` only in doc-link paths.
#
# Vendored as a path dependency like `tinyhumans-sdk`: the crate is not
# published to crates.io, so there is no `[patch.crates-io]` entry for it.
# After cloning: `git submodule update --init vendor/tinydocs`.
#
# Optional: exclusive to the `documents` feature, which is **default-OFF,
# product-ON** — `[features] default` is the contributor set and this is not in
# it; `scripts/ci/product-features.txt` is what the shipped desktop app has, and
# it is. The comment here said "default-ON", which was true before #4919 split
# the two sets and has been wrong since.
tinydocs-bus = { path = "vendor/tinydocs/crates/tinydocs-bus", optional = true }
# TinyVoice — the voice wire contract, and nothing else.
#
# Same arrangement as `tinydocs-bus`: member names, the payload types the
# module answers with, and the contract version, at a cost of `serde`. The
# processing lives in the `tinyvoice` TinyBus module, so nothing here decodes
# audio. `src/openhuman/modules/voice.rs` used to redeclare these types with a
# comment saying it did so because this crate did not depend on TinyVoice;
# it does now.
#
# After cloning: `git submodule update --init vendor/tinyvoice`.
#
# Optional: exclusive to the `voice` feature — default-OFF, product-ON, the
# same split as `documents` above.
tinyvoice-bus = { path = "vendor/tinyvoice/crates/tinyvoice-bus", optional = true }
# TinyJuice — the compression wire contract, and nothing else.
#
# Same arrangement as `tinydocs-bus` and `tinyvoice-bus`: the payload types, the
# request and response envelopes, the member names and the contract version, at
# a cost of `serde`. The router, the compressors, the CCR cache and the rule
# engine all live in the `tinyjuice` module and are not in this build.
#
# `src/openhuman/inference/tokenjuice/types.rs` was a 259-line hand-copy of
# these types headed "Stable wire types shared with the separately compiled
# TinyJuice module" — shared by convention and checked by nobody. It is a
# re-export now.
#
# Not optional: `inference::tokenjuice` is always compiled (the compression
# middleware sits in the agent turn path, which is kernel), so the contract has
# no gate to hang off.
#
# After cloning: `git submodule update --init vendor/tinyjuice`.
tinyjuice-bus = { path = "vendor/tinyjuice/crates/tinyjuice-bus" }
# TinyHosts — the unified hosting API: one `Host` trait over a hosting provider,
# and the `launch` flow that puts a Next.js application, its database, its
# environment and its domains on it in the one order that works.
#
# The provider vocabulary stops inside the crate. What OpenHuman gets is the
# model — sites, deployments, databases, domains, analytics — so which provider
# a user pastes a key for is a config value here rather than a code path.
#
# Taken with the `vercel` provider only, which is the one that exists.
#
# Vendored as a path dependency like `tinyhumans-sdk`: the crate is not
# published to crates.io, so there is no `[patch.crates-io]` entry for it.
# After cloning: `git submodule update --init vendor/tinyhosts`.
#
# Optional: exclusive to the default-OFF `hosting` feature.
tinyhosts = { path = "vendor/tinyhosts", default-features = false, features = ["vercel"], optional = true }
# TinyWallet — host-agnostic multi-chain wallet primitives. Owns the address
# formats themselves: parsing, validation, and the conversions between their
# encodings for Bitcoin, EVM chains, Solana and Tron. Nothing about "is this a
# well-formed Solana address" is OpenHuman-specific, so the rules live where
# any host can reach them. What stays in `src/openhuman/web3/` is everything
# the crate deliberately refuses to own: RPC endpoint resolution, transaction
# assembly and broadcast, and key custody.
#
# Vendored as a path dependency like `tinyhumans-sdk`: the crate is not
# published to crates.io, so there is no `[patch.crates-io]` entry for it.
# After cloning: `git submodule update --init vendor/tinywallet`.
#
# Optional: exclusive to the `web3` feature — OFF in the contributor set
# (`[features] default`) and ON in the product set
# (`scripts/ci/product-features.txt`), so it ships but a bare `cargo check` does
# not pay for it. See the two-set note above `default`.
#
# Taken as `tinywallet-bus`, the contract crate, and NOT the root `tinywallet`
# crate. The root crate is where key derivation, transaction building, signing
# and the chain clients live, and those are the gates that pull the `bitcoin`
# crate and its native secp256k1 build; all of it happens inside the loaded
# `tinywallet` module now, so this binary links none of it. What the contract
# crate carries is exactly what a host still runs itself: the wire types that
# cross the bus, the bus member names, address validation, the EIP-712 and ERC-20
# encoders the x402 payment path builds with, the `Transport` seam this crate
# implements, and the Tron verifier that checks what a node handed back before
# a transaction is sent for signing.
#
# The root crate is still taken under [dev-dependencies], where test fixtures
# derive a known account. Dev-dependency features are not linked into the
# shipped binary, so that does not undo the shed.
tinywallet-bus = { path = "vendor/tinywallet/crates/tinywallet-bus", default-features = false, features = ["btc", "evm", "solana", "tron", "keccak", "net", "wire", "eip712", "abi", "tx-codec"], optional = true }
# secp256k1 signing over the digests the wallet module hands back. Pure Rust,
# and already in the graph beneath `coins-bip32` (which derives the key being
# used, via tinywallet's `key` gate), so naming it directly costs nothing and
# is what lets `bitcoin` go.
k256 = { version = "0.13", default-features = false, features = ["std", "ecdsa"], 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.29", 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.29", default-features = false, features = ["connect", "handshake", "rustls-tls-webpki-roots"] }
[target.'cfg(target_os = "linux")'.dependencies]
landlock = { version = "0.4", optional = true }
rppal = { version = "0.22", optional = true }
[dev-dependencies]
# Test fixtures derive a known account from the BIP-39 vector phrase. Production
# does not derive at all — see the note on the main `tinywallet` entry. Cargo
# does not link dev-dependency features into the shipped binary, so enabling
# `key` here does not put the derivation stack back into the product.
tinywallet = { path = "vendor/tinywallet", default-features = false, features = ["key", "btc", "evm", "solana", "tron"] }
k256 = { version = "0.13", default-features = false, features = ["std", "ecdsa"] }
coins-bip39 = { version = "0.8" }
# The host's own tests drive `tinymemory-core`'s test helpers
# (`chat::test_override`, `StaticChatProvider`, `tool_memory::test_helpers`).
# They were `#[cfg(test)]` items in this crate before the memory extraction; a
# downstream test harness cannot see those across a crate boundary, so the
# extracted crate exposes them behind `test-support` instead.
tinymemory-core = { path = "vendor/tinymemory/crates/tinymemory-core", features = ["test-support"] }
# Dual-declared on purpose (same shape as the `sentry`/`axum` entries): the
# optional dependency above is bin-only behind `bin-tools`, but
# `agent_orchestration::tools::tools_e2e_tests` (a #[cfg(test)] LIB module),
# `tests/memory_graph_sync_e2e.rs`, `tests/x402_twit_sh_live.rs` and
# `examples/embed_headless.rs` all call it with no feature #[cfg]. Without this
# line the test build breaks the moment `bin-tools` is off.
env_logger = "0.11"
# 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]
# THE CONTRIBUTOR SET — not the product set.
#
# This list is what a bare `cargo check`, `cargo test` and rust-analyzer
# compile. It is deliberately SMALLER than what the desktop app ships: the
# product set lives in `scripts/ci/product-features.txt` and is forwarded
# explicitly by `app/src-tauri/Cargo.toml`, with
# `scripts/ci/check-feature-forwarding.mjs` asserting the two are equal in both
# directions. Read that file's header before changing either list.
#
# Why the split: the gates left ON below cost almost nothing to compile, so
# keeping them on means `cargo check` and rust-analyzer still typecheck nearly
# all of the tree. The gates turned OFF are the ones that carry the graph —
# web3's ethers/secp256k1 cohort, `documents`' zstd/bzip2 native builds,
# `voice`+`inference`'s cpal/lettre/arboard/enigo/rdev stack, `contacts`'
# macOS objc2 cohort, `crash-reporting`'s sentry tree, and `tui`'s
# ratatui/crossterm. Turning them off takes a
# bare `cargo check` from 540 packages / 7 native builds down to ~350 / 2, which
# is the inner loop every contributor pays on every edit.
#
# THIS DOES NOT CHANGE WHAT SHIPS. The desktop shell has always set
# `default-features = false` (#1061), so it never inherited this list to begin
# with — that is exactly why the forwarding guard had to exist. What DOES
# change is that a lane relying on default features no longer covers the
# gated-off domains, so every CI lane that builds or tests "the product" now
# passes `--features "$(scripts/ci/product-features.sh)"`. If you add a lane,
# decide which of the two sets it is testing and say so.
# `modules` is in this list because the memory seam is not optional at test
# time. `memory::binding::module_provider` has a `#[cfg(not(feature =
# "modules"))]` arm that binds `NullMemoryProvider`, so without the gate a bare
# `cargo test --lib -- memory::` fails 26 tests, every one of them a "null vs
# module" assertion, and 15 further module-gated tests do not exist at all
# (582 passed / 26 failed, versus 623 passed / 0 failed with the gate on).
# A default set that cannot run its own test suite is not a usable inner loop.
# The cost is the smallest of any gate here: +9 packages / +5 unique names
# (`ureq`, `ureq-proto`, `utf8-zero`, `toml_edit`, `toml_write`) and **zero**
# new native builds — the native list is byte-identical with the gate on and
# off. That is nothing like the cohorts #4919 moved out of `default`, and it
# also brings the build in line with what AGENTS.md has always documented
# (`modules`: Contrib=ON, Product=ON) and with `scripts/ci/product-features.txt`,
# which already lists it. This does NOT move the kernel floor: that profile is
# `--no-default-features --features flows` and never reads this list.
default = ["media", "skills", "flows", "mcp", "channels", "medulla", "http-server", "scheduler-gate", "file-logging", "modules"]
# 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 "<explicit list without
# http-server>"`, 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`.
# Git-backed memory diff: snapshots as commits, checkpoints as tags, read
# markers as refs, diffs as git tree diffs (`openhuman::memory::diff`), plus the
# git-backed wiki content format in `memory::store::content::wiki_git`.
# Default-OFF, product-ON.
#
# The most expensive gate in the tree by native-build cost: it turns on
# tinycortex's `git-diff`/`wiki-git`, which carry `git2` with vendored libgit2,
# so turning it off drops `git2` + `libgit2-sys` + `libz-sys` and takes the
# kernel profile from 5 native C builds to 3. The cohort enters the graph
# through tinycortex only — this crate declares no `git2` of its own (see the
# note where it used to sit in `[dependencies]`).
#
# TYPE CARVE-OUT (see AGENTS.md): `memory::diff::types` stays compiled in BOTH
# builds. It re-exports tinycortex's `serde`-only diff wire types, which the
# always-on subconscious memory profile renders into prompts; a stub copy would
# be a second definition of one serde shape, free to drift. tinycortex makes the
# same split — its `memory::diff::{types,source}` are ungated, and only the
# git-touching `ledger`/`DiffEngine` half sits behind `git-diff`.
#
# Off-state: the `memory_diff` RPC namespace is unknown-method and absent from
# `/schema`; the `memory_diff` agent tool is absent from the tool list; the
# embedded driver stops advertising `Capability::Diff` and `as_diff()` returns
# `None`; and the three `ops` entry points always-on code calls return a
# build-fact error, so a post-sync snapshot or a subconscious diff is logged and
# skipped rather than silently reported as "nothing changed".
memory-git = ["tinycortex/git-diff", "tinycortex/wiki-git", "tinymemory-core/memory-git"]
http-server = ["dep:axum", "dep:socketioxide"]
# Local audio-device access: the `cpal` capture stack behind voice recording
# and the accessibility microphone-permission probe. Default-ON. Slim /
# headless builds opt out via `--no-default-features --features "<explicit list
# without inference>"`, which drops the exclusive `cpal` dependency; the
# microphone probe then reports `Unknown`. `voice` requires this gate, so
# building `voice` always pulls `inference` in transitively.
#
# NOTE ON THE NAME (do not "fix" it to `audio`): this gate used to cover the
# bundled whisper.cpp STT engine (`whisper-rs` + the `whisper-rs-sys` CRT
# patch) as well. That engine is gone — STT is now cloud/engine-configurable
# only (`voice_server.stt_engine`, `voice::factory`) — so `cpal` is all that is
# left behind the gate. The gate name stays `inference` because it is forwarded
# by name from `app/src-tauri/Cargo.toml`, asserted by `INFERENCE_COMPILED_IN`,
# and referenced from `desktop::accessibility::permissions`; renaming it buys
# nothing and would silently drop the microphone probe from the shipped app if
# the forwarding list were not updated in lockstep.
inference = ["dep:cpal"]
# Office-document tools: the `generate_document` and `generate_presentation`
# agent tools, plus PDF text extraction during multimodal file ingest.
# Default-ON.
#
# The synthesis is NOT in this build. All three run in the `tinydocs` TinyBus
# module, downloaded and verified at first use (`src/openhuman/modules/`), so
# this gate turns on the tools and the host policy around them — the artifact
# pipeline, the deadlines, image resolution under the security policy — and
# `tinydocs` is here for the wire contract only. `docx-rs`, `ppt-rs` and
# `pdf-extract` are not in the dependency graph in any configuration.
#
# 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`). Slim / headless builds opt out via
# `--no-default-features --features "<explicit list without documents>"`.
documents = ["modules", "dep:tinydocs-bus"]
# Hosting: the `hosting_*` agent tools that put a workspace on a real hosting
# provider — a site, a managed database wired into it, its environment, its
# domains, its deployments and the traffic they served. Default-OFF,
# product-ON: a host with no hosting credential has no use for the tools, and
# an agent that can deploy to the internet is authority a headless embedding
# should have to ask for.
#
# Leaf gate: when off, `openhuman::hosting` is not compiled and the tools are
# absent from the registry rather than degraded to an error. When on, they are
# still only registered once a credential actually resolves — from
# `[hosting].api_key` or the provider's environment variable — because a tool
# that cannot work is worse than a tool that is not there.
hosting = ["dep:tinyhosts"]
# The dynamic module host (`openhuman::modules`): the loader that admits a
# compiled `cdylib` through tinybus's ABI descriptor, manifest, dependency and
# SHA-256 gates, plus the `modules` RPC namespace and the registry of modules
# this build trusts. Default-ON, and implied by every gate whose work happens in
# a module — today that is `documents`.
#
# Off ⇒ the `modules.*` controllers are unregistered (unknown-method over
# `/rpc`, absent from `/schema`) and nothing can load a native module. Forwarding
# `tinybus/modules` here rather than on the dependency itself keeps the loader
# out of the kernel profile, where `tinybus` is always-on: a workflow-only host
# should not carry `ureq` and an archive stack to support a loader it cannot use.
#
# A loaded module is trusted in-process code with this process's privileges, and
# tinybus never unloads one. See `src/openhuman/modules/` before adding an entry
# to the registry.
modules = ["tinybus/modules"]
# 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 "<explicit list without voice>"`,
# which also drops the exclusive `lettre` (podcast email) dependency. `hound`
# used to be on that list; WAV framing moved to the `tinyvoice` module, so the
# crate left this graph entirely rather than merely being gated. Composes with the runtime `DomainSet::voice` flag (#4796): the
# feature narrows the compile-time surface, `DomainSet` gates it at runtime.
# Requires `inference` (the cpal capture stack), so enabling `voice` turns
# `inference` on transitively.
# `arboard`/`enigo`/`rdev` join here rather than getting their own gate: their
# only call sites are `voice::text_input` (clipboard + synthetic keystrokes to
# insert a dictated transcript) and `voice::hotkey` (the global push-to-talk
# listener), both already `#[cfg(feature = "voice")]`, and nothing outside
# `voice/` reaches them. Worth 17 crates — the largest single shed in the wave —
# because `arboard` alone drags an X11/wayland clipboard stack (11 crates) into
# any build that just wants workflow execution.
voice = [
"inference",
# Wake-word gating, command routing and hallucination detection run in the
# `tinyvoice` module, so the voice domain needs the module host the same way
# `documents` needs it for `tinydocs`. Without this, `--features voice`
# alone fails to resolve `openhuman::modules` — which the product build
# hides, because `documents` turns `modules` on anyway.
"modules",
# The member names and payload types the module answers with. Contract
# only — `serde` and nothing else.
"dep:tinyvoice-bus",
"dep:lettre",
"dep:arboard",
"dep:enigo",
"dep:rdev",
# `audio_toolkit::ops` delivers generated podcasts through tinychannels'
# EmailChannel, so the provider has to exist even in a channels-less build.
"tinychannels/email",
]
# Web3 family: openhuman::web3 + web3::wallet + web3::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 "<explicit list without web3>"`, which
# drops the exclusive `bitcoin` (P2WPKH PSBT) + `curve25519-dalek` (Solana
# off-curve ATA) + `ethers-core` / `ethers-signers` / `coins-bip39` (EVM/mnemonic
# signing, used by the multi-chain wallet's EVM path) dependencies. Composes
# with the runtime `DomainSet::Web3` flag (#4796): the feature narrows the
# compile-time surface, `DomainSet` gates it at runtime. When off, tinyplace
# payments degrade to graceful "wallet disabled" errors via the wallet/web3/x402
# stub facades.
#
# `bs58` and `ed25519-dalek` deliberately stay always-on: `orchestration/ingest`
# and `tinyplace/payment` use them for agent-network identity, which has nothing
# to do with the wallet. Measured: excluding them costs 0, because tinyplace
# pulls them in regardless.
# `k256` and `coins-bip39` are gone from this list: nothing in the shipped
# binary derives a key or signs with secp256k1 any more — the wallet module
# does both. Both crates remain under [dev-dependencies], where test fixtures
# still derive a known account and check a signature against a fixed vector.
#
# `curve25519-dalek` stays: `associated_token_account` needs the off-curve check
# to derive a Solana ATA, which is address arithmetic rather than signing, and
# tinyplace pulls it in through `ed25519-dalek` regardless.
web3 = [
"dep:tinywallet-bus",
"dep:curve25519-dalek",
"modules",
]
# Managed Node.js runtime: `runtime::node` (the client that asks the
# `tinyruntime` module for a toolchain), the `runtime::javascript` language slot
# over it, `runtime::pool::node`, the `node_exec` / `npm_exec` agent tools, and
# the `node_runtime` harness-init step. Default-ON. Slim builds opt out via
# `--no-default-features --features "<list without runtime-node>"`.
#
# This gate no longer sheds a dependency. It used to carry the exclusive `xz2`
# and its static liblzma C build; downloading and unpacking a toolchain moved to
# the `tinyruntime` module, so that native build left this manifest for every
# configuration rather than only for slim ones. What the gate still buys is the
# absence of the tools and controllers themselves.
#
# FACADE + STUB, not a leaf gate. `ShellTool` holds `Option<Arc<NodeBootstrap>>`
# for managed-Node PATH injection and `tools/impl/system/shell.rs` is kernel, so
# deleting the module would take the shell tool with it. `runtime/node/stub.rs`
# carries the `NodeBootstrap` type surface; registration sites (`node_runtime_step`,
# the `javascript` controllers, `node_exec`/`npm_exec`) are leaf-gated at their call
# sites, because registration sites want absence.
#
# The generic native-tool dispatcher (`runtime::node::ops` / `runtime::node::types`)
# is deliberately NOT gated: it backs both the gated `javascript.*` controllers and
# the ungated `flows` `oh:` `NativeToolBackend`, so native flow tools keep working
# when the managed Node runtime is compiled out.
#
# Off-state: `try_cached`/`probe_installed` return `None`, so the shell never
# prepends a managed bin dir — identical to today's `node.enabled = false` path.
runtime-node = []
# macOS Contacts seeding for the people domain: `memory::people::address_book`
# reads CNContactStore to seed handles. Default-ON. Slim / headless builds opt
# out via `--no-default-features --features "<list without contacts>"`, which
# sheds the exclusive `objc2` / `objc2-foundation` / `objc2-contacts` / `block2`
# cohort on macOS. Leaf gate with a pre-existing off-state: `address_book.rs`
# already carries a non-macOS `imp` stub returning an empty contact list, so the
# gate simply widens that stub's cfg — `read()`, `read_with()`,
# `AddressBookError` and `SystemContactsSource` stay compiled in every build and
# the `people` RPC surface is unchanged. Off ⇒ address-book refresh seeds
# nothing instead of failing.
#
# NOTE: no-op on Linux/Windows, where these crates were never in the graph.
# Verify the shed cross-target from any host:
# cargo tree --target aarch64-apple-darwin -e normal -i objc2-contacts \
# --no-default-features
#
# ── This gate is FORWARDED, and it was silently broken before it was ─────────
# The reader has never lived in this crate. It sits in the memory engine, and
# this feature used to enable four `objc2` crates *here* — which no file in
# `src/` names — while never reaching the crate that holds the `#[cfg]`. So the
# macOS arm of `address_book.rs` was always compiled out: `SystemContactsSource`
# returned the empty stub, `people.refresh_address_book` reported success having
# seeded nothing, and macOS paid to compile four unused crates for the trouble.
#
# That is the exact soft-failure shape as `voice` (#4901) and
# `tokenjuice-treesitter` (#4918): a gate that is not forwarded does not fail
# the build, it just quietly does nothing. Hence the forward below, and
# `contacts_feature_reaches_the_engine_reader` in `memory/people/mod.rs`, which
# fails if this is ever flattened back into local `dep:` entries.
contacts = ["tinymemory-core/contacts"]
# 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 "<explicit list without media>"`.
# 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 "<list without flows>"`,
# which drops `tinyflows` + its `jaq-core`/`jaq-std`/`jaq-json` JSON-query stack
# (the `rhai` scripting engine no longer rides along: tinyagents dropped its
# `repl`/`rlm` features, and nothing here referenced them). 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.
flows = ["dep:tinyflows"]
# Skills domains: `openhuman::skills` (metadata/discovery/install),
# `openhuman::skill_runtime` (SKILL.md execution + the skill_executor agent),
8
0