forked from tinyhumansai/openhuman
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathCargo.toml
More file actions
824 lines (793 loc) · 46 KB
/
Copy pathCargo.toml
File metadata and controls
824 lines (793 loc) · 46 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
[package]
name = "openhuman"
version = "0.63.6"
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"
[[bin]]
name = "openhuman-core"
path = "src/main.rs"
[[bin]]
name = "slack-backfill"
path = "src/bin/slack_backfill.rs"
required-features = ["bin-tools"]
[[bin]]
name = "gmail-backfill-3d"
path = "src/bin/gmail_backfill_3d.rs"
required-features = ["bin-tools"]
[[bin]]
name = "memory-tree-init-smoke"
path = "src/bin/memory_tree_init_smoke.rs"
required-features = ["bin-tools"]
[[bin]]
name = "inference-probe"
path = "src/bin/inference_probe.rs"
required-features = ["bin-tools"]
[[bin]]
name = "harness-subagent-audit"
path = "src/bin/harness_subagent_audit.rs"
required-features = ["bin-tools"]
[[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"]
[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/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.
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 = { version = "0.11", optional = true }
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 = { 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"
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"], 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 }
whisper-rs = { version = "0.16", optional = true }
tempfile = "3"
cpal = { version = "0.15", optional = true }
hound = { version = "3.5", 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 }
ethers-core = { version = "2.0.14", default-features = false, optional = true }
ethers-signers = { version = "2.0.14", default-features = false, 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.
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 = { 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"] }
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]
# 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]
default = ["tokenjuice-treesitter", "inference", "voice", "web3", "media", "documents", "meet", "skills", "flows", "mcp", "crash-reporting", "http-server", "channels", "tui", "medulla", "scheduler-gate", "file-logging", "prediction-markets"]
# 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`.
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 "<explicit list without inference>"`, 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 "<explicit list without
# documents>"`, 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 "<explicit list without voice>"`,
# 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.
# `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",
"dep:hound",
"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 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.
# The EVM/mnemonic crypto stack now belongs to this gate. It previously did
# not, because the Polymarket tools (`tools/impl/network/polymarket*`,
# `clob_auth`) consumed `ethers-*`/`coins-bip39` while living outside the
# wallet/web3/x402 domains — so the gate could not shed them and AGENTS.md said
# so in writing. `prediction-markets` below resolves that by giving Polymarket
# its own gate that implies this one, which makes the whole cohort droppable:
# -67 crates, the largest single shed in the kernelization work.
#
# `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.
web3 = [
"dep:bitcoin",
"dep:curve25519-dalek",
"dep:ethers-core",
"dep:ethers-signers",
"dep:coins-bip39",
]
# Polymarket prediction-market tools (read + trading). Implies `web3` because it
# signs orders with the same EVM stack the wallet uses — an honest dependency
# rather than a hidden one. Separate from `web3` so a build can have a wallet
# without a trading surface; the reverse is not meaningful.
prediction-markets = ["web3"]
# 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
# 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 "<list without
# meet>"`. 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 "<explicit list without skills>"`.
# 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, all under the `mcp/` family: `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::config_servers`. 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: the family root `pub mod mcp;` and `mcp::http_client` stay ALWAYS
# compiled. `http_client` is a mis-housed shared utility (the gitbooks docs
# tool dials `McpHttpClient`; `core::observability` names
# `McpUnauthorizedError`), and the server/registry/audit stubs need their
# parent compiled. `sanitize` left the family entirely for `util::sanitize` —
# the orchestrator prompt sanitises *skill* descriptions through it. 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
# "<explicit list without crash-reporting>"`, 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 "<explicit list without tui>"`, 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` 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
# "<explicit list without channels>"`. 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`.
# Provider modules inside tinychannels are now feature-gated there, so this
# gate finally sheds crates instead of being surface-only: `email` owns the
# lettre/async-imap/mail-parser stack and `lark` owns axum + prost — 27 crates
# that a workflow-only build has no use for. The crate itself still cannot be
# dropped (DomainEvent embeds its inbound envelope, config re-exports its
# provider types, security::pairing re-exports its helpers), which is why
# gating the providers rather than the crate is the right seam.
channels = ["tinychannels/email", "tinychannels/lark"]
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.
# CLI argument parsing + logger init for the six developer/ops binaries under
# `src/bin/`. Default-OFF and NOT in `default`: nothing in the library reaches
# `clap` or `env_logger` (the one hit in `core/logging.rs` is a doc comment),
# so the shipped desktop build has no reason to carry a 14-crate CLI stack.
# Each owning `[[bin]]` declares `required-features = ["bin-tools"]`, so those
# targets are simply skipped rather than failing to link when it is off.
# Battery/AC probe feeding the scheduler's throttle decision. Default-ON.
# When off there is no hardware probe: `sample_power` reports "on AC, no charge
# signal", which is the same answer the real probe gives on a server or
# container. Consequence to be explicit about — `require_ac_power` and
# `battery_floor` are NOT enforced in such a build. CPU throttling and
# server-mode detection are unaffected.
# Rolling on-disk log files, plus the `log`->`tracing` bridge. Default-ON.
# Two consequences worth being explicit about when it is off:
# * nothing is written to disk, so a packaged desktop build has no durable
# log to attach to a support request. stderr and Sentry are unaffected.
# * `tracing-log` goes with it, so `log::*` records from dependencies stop
# reaching tracing in EVERY init path — including the stderr-only CLI one,
# which otherwise has nothing to do with file logging.
# `tracing` and `tracing-subscriber` are NOT part of this gate and stay always-on.
file-logging = ["dep:tracing-appender", "dep:tracing-log"]
scheduler-gate = ["dep:starship-battery"]
bin-tools = ["dep:clap", "dep:env_logger"]
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