Repository navigation
Expand file tree
/
Copy pathCargo.toml
More file actions
1344 lines (1303 loc) · 77.3 KB
/
Copy pathCargo.toml
File metadata and controls
1344 lines (1303 loc) · 77.3 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
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
[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.
# `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 NO
8
T enable
10BC8
d 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),