Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
490111e
fix(tinyflows): preserve explicit node timeouts, align discover timeo…
graycyrus Jul 15, 2026
8800f1e
chore(release): merge release v0.61.2 back into main
github-actions[bot] Jul 15, 2026
ad771fd
feat(flows): workflow-builder agent-friendliness plumbing — schema-aw…
senamakel Jul 15, 2026
2cbf630
fix(flows): guarantee a terminal state on every flows_build turn (no …
graycyrus Jul 15, 2026
ece3420
fix(flows): save-safety — no silent live-arming on update, flag empty…
graycyrus Jul 15, 2026
1ddd675
fix(flows): copilot proposals reach the canvas — recognition, race-gu…
graycyrus Jul 15, 2026
fe2a304
fix(flows): live-updating runs lists + row-action cleanup (enable tog…
graycyrus Jul 15, 2026
390c1ca
fix(flows): exempt workflow proposal tools from tokenjuice compaction…
graycyrus Jul 15, 2026
0e86b85
fix(flows): close stale-read race in flows_update disarm + actionable…
graycyrus Jul 15, 2026
095e3c3
fix(chat): don't wipe fresh streaming/tool-timeline on a completed hy…
graycyrus Jul 15, 2026
5ba512b
fix(flows): correct save_workflow + workflow_builder contract text (d…
graycyrus Jul 15, 2026
2dcaaba
feat(core): compile-time media feature gate (media_generation + image…
oxoxDev Jul 15, 2026
eae6f9d
fix(flows): canvas Accept persists the proposal (accept = review + sa…
graycyrus Jul 15, 2026
5171f5c
fix(flows): circuit-breaker counts validate/dry_run body-level ok:fal…
graycyrus Jul 15, 2026
45dc6c0
chore(staging): merge release v0.61.3-staging back into main
github-actions[bot] Jul 15, 2026
3cca4f3
chore(release): merge release v0.61.4 back into main
github-actions[bot] Jul 15, 2026
4135cfc
feat(rewards): surface the Rewards page via a cloud-gated sidebar foo…
YellowSnnowmann Jul 15, 2026
1feb873
fix(flows): show "awaiting approval" state in runs lists when a run i…
graycyrus Jul 15, 2026
d320c43
chore(rust): enforce warning-free clippy (#4872)
senamakel Jul 15, 2026
bfaa261
fix(theme): polish Matrix + HAL 9000 (and other dark) presets to WCAG…
M3gA-Mind Jul 15, 2026
a41c21a
fix(voice): ship the voice domain in the desktop build (#4901) (#4917)
CodeGhost21 Jul 15, 2026
4be1763
chore(release): merge release v0.61.5 back into main
github-actions[bot] Jul 15, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 23 additions & 4 deletions .github/workflows/ci-lite.yml
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,7 @@ jobs:
with:
workspaces: |
. -> target
app/src-tauri -> target
cache-on-failure: true
# shared-key (not key) so the cache name is stable and not suffixed
# with the job id. Swatinem caches the full target/, which is why we
Expand All @@ -349,13 +350,31 @@ jobs:
run: cargo fmt --all -- --check

- name: Run clippy (core crate)
run: bash scripts/ci-cancel-aware.sh cargo clippy -p openhuman
if: needs.changes.outputs['rust-core'] == 'true'
run: bash scripts/ci-cancel-aware.sh cargo clippy -p openhuman -- -D warnings

- name: Cache CEF binary distribution
if: needs.changes.outputs['rust-tauri'] == 'true'
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
with:
path: |
~/Library/Caches/tauri-cef
~/.cache/tauri-cef
key: cef-x86_64-unknown-linux-gnu-v2-${{ hashFiles('app/src-tauri/Cargo.toml') }}
restore-keys: |
cef-x86_64-unknown-linux-gnu-v2-

- name: Run clippy (Tauri shell)
if: needs.changes.outputs['rust-tauri'] == 'true'
run: bash scripts/ci-cancel-aware.sh cargo clippy --manifest-path app/src-tauri/Cargo.toml -- -D warnings

# Feature-gate smoke: proves the core still compiles with a domain gate turned
# OFF. The disabled build is the ONLY thing that catches stub-facade signature
# drift (see AGENTS.md "Compile-time domain gates"), so it must run in CI, not
# just locally. Pathfinder lane for #4803 (voice); extend the --features list
# as sibling gates (#4797–#4802, #4804) land.
# just locally. Pathfinder lane for #4803 (voice); the explicit --features
# list (only tokenjuice-treesitter) turns every default gate OFF, so it also
# covers #4804 (media) and each sibling gate as it lands — no edit needed
# unless a new gate must stay ON here.
rust-feature-gate-smoke:
name: Rust Feature-Gate Smoke (gates off)
needs: [changes]
Expand All @@ -382,7 +401,7 @@ jobs:
cache-on-failure: true
shared-key: pr-rust-feature-gate-smoke

- name: Check core builds with the voice gate disabled
- name: Check core builds with the voice + media gates disabled
run: bash scripts/ci-cancel-aware.sh cargo check --manifest-path Cargo.toml --no-default-features --features tokenjuice-treesitter

rust-core-coverage:
Expand Down
12 changes: 6 additions & 6 deletions .husky/pre-push
Original file line number Diff line number Diff line change
Expand Up @@ -93,10 +93,10 @@ pnpm compile
COMPILE_EXIT=$?
set -e

# Run Rust compile checks for both the core and Tauri codebases
# Run Clippy for both Rust codebases; Clippy also performs compile checks.
set +e
pnpm rust:check
RUST_CHECK_EXIT=$?
pnpm rust:clippy
RUST_CLIPPY_EXIT=$?
set -e

# Enforce scoped cmd-* tokens in components/commands/
Expand All @@ -106,7 +106,7 @@ CMD_TOKENS_EXIT=$?
set -e

# Exit with error if any command still fails after fixes
if [ $FORMAT_EXIT -ne 0 ] || [ $LINT_EXIT -ne 0 ] || [ $COMPILE_EXIT -ne 0 ] || [ $RUST_CHECK_EXIT -ne 0 ] || [ $CMD_TOKENS_EXIT -ne 0 ]; then
if [ $FORMAT_EXIT -ne 0 ] || [ $LINT_EXIT -ne 0 ] || [ $COMPILE_EXIT -ne 0 ] || [ $RUST_CLIPPY_EXIT -ne 0 ] || [ $CMD_TOKENS_EXIT -ne 0 ]; then
echo
echo "============================================================"
echo "Pre-push checks failed."
Expand All @@ -116,10 +116,10 @@ if [ $FORMAT_EXIT -ne 0 ] || [ $LINT_EXIT -ne 0 ] || [ $COMPILE_EXIT -ne 0 ] ||
echo " git add -A && git commit -m 'chore: apply auto-fixes'"
echo " git push"
fi
if [ $COMPILE_EXIT -ne 0 ] || [ $RUST_CHECK_EXIT -ne 0 ] || [ $CMD_TOKENS_EXIT -ne 0 ]; then
if [ $COMPILE_EXIT -ne 0 ] || [ $RUST_CLIPPY_EXIT -ne 0 ] || [ $CMD_TOKENS_EXIT -ne 0 ]; then
echo "Fix the remaining errors above (TypeScript / Rust / cmd-tokens)"
echo "before re-pushing — these have no auto-fix path."
fi
echo "============================================================"
exit 1
fi
fi
3 changes: 3 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -233,11 +233,14 @@ GGML_NATIVE=OFF cargo check --manifest-path Cargo.toml \
| Feature | Default | Gates | Drops deps |
| ------- | ------- | ----- | ---------- |
| `voice` | ON | `openhuman::voice` + `openhuman::audio_toolkit` domains — STT/TTS providers, dictation server, always-on listening, podcast audio + email | `hound`, `lettre` |
| `media` | ON | `openhuman::media_generation` (the `media_generate_*` agent tools) + `openhuman::image` scaffold | none (surface-only) |

**Facade pattern (pathfinder for the other gates).** `pub mod voice;` is **always compiled** as a facade: the real submodules are `#[cfg(feature = "voice")]`, and a `#[cfg(not(feature = "voice"))] mod stub;` (`src/openhuman/voice/stub.rs`) re-exposes the same public surface that always-on / other-gated callers use (`server`, `dictation_listener`, `streaming`, `reply_speech`, `cloud_transcribe`, `cli`, `create_stt_provider`, `effective_stt_provider`, `publish_ptt_transcript_committed`) with no-op / `None` / disabled-error bodies. Callers therefore do **not** need per-call `#[cfg]`. When voice is off: the voice/audio controllers are unregistered (unknown-method over `/rpc`, absent from `/schema`), the `audio_generate_podcast` agent tools are absent, and `openhuman voice` returns a "voice disabled" error. Stub signatures must match the real ones exactly — the disabled build (`--no-default-features --features tokenjuice-treesitter`) is the **only** thing that catches drift, so run it before pushing any change to the voice surface.

**Scope note:** the `voice` gate does **not** drop `whisper-rs` / `llama` / `cpal`. Those live in the inference domain (`src/openhuman/inference/local/service/whisper_engine.rs`; `cpal` is shared with accessibility) and await a separate future `inference` gate. The issue-level DoD line claiming whisper is dropped is superseded by this scope correction.

**Leaf-gate variant (`media`, #4804).** Unlike `voice`, the `media` gate needs **no** stub facade: `media_generation` has a single caller (the `build_media_tools` call in `src/openhuman/tools/ops.rs`, itself `#[cfg(feature = "media")]`) and `openhuman::image` is unwired scaffold (#2997), so both modules are simply `#[cfg(feature = "media")] pub mod …`. It is a **surface-only** gate: media generation is backend-proxied (`reqwest`, shared) and the `image` crate is shared with channel upload, so no exclusive deps are shed — the issue's "sheds media processing dependencies" / "controllers unregistered" DoD lines are superseded (Media is agent-tools-only; no controller/store/subscriber is tagged `Media`). When a gated domain is a true leaf, prefer this over the facade+stub.

### Event bus (`src/core/event_bus/`)

Typed pub/sub + native request/response. Both singletons — use module-level functions.
Expand Down
27 changes: 26 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,7 @@ tokio = { version = "1", features = ["test-util"] }
proptest = "1"

[features]
default = ["tokenjuice-treesitter", "voice"]
default = ["tokenjuice-treesitter", "voice", "media"]
# 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 = [
Expand All @@ -351,6 +351,18 @@ tokenjuice-treesitter = [
# inference domain (shared with accessibility for cpal) and await a separate
# `inference` gate.
voice = ["dep:hound", "dep:lettre"]
# 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) and the `image` crate is shared with
# channel media upload. 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 = []
sandbox-landlock = ["dep:landlock"]
sandbox-bubblewrap = []
peripheral-rpi = ["dep:rppal"]
Expand All @@ -367,6 +379,19 @@ e2e-test-support = []
[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.
Expand Down
2 changes: 1 addition & 1 deletion app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@
"rust:check": "cargo check --manifest-path src-tauri/Cargo.toml",
"rust:format": "cargo fmt --manifest-path ../Cargo.toml --all && cargo fmt --manifest-path src-tauri/Cargo.toml --all",
"rust:format:check": "cargo fmt --manifest-path ../Cargo.toml --all --check && cargo fmt --manifest-path src-tauri/Cargo.toml --all --check",
"rust:clippy": "cargo clippy -p openhuman -- -D warnings",
"rust:clippy": "cargo clippy --manifest-path src-tauri/Cargo.toml -- -D warnings",
"format": "prettier --write . && pnpm rust:format",
"format:check": "prettier --check . && pnpm rust:format:check",
"lint": "eslint . --ext .ts,.tsx --cache",
Expand Down
8 changes: 8 additions & 0 deletions app/src-tauri/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

28 changes: 26 additions & 2 deletions app/src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,31 @@ cef = { version = "=146.4.1", default-features = false }
# by tying the core's lifetime to the GUI process. The existing port-7788
# probe in `core_process::ensure_running` still attaches to a running
# `openhuman-core run` harness when one is already listening.
openhuman_core = { path = "../..", package = "openhuman", default-features = false }
#
# `default-features = false` (set in #1061, before the compile-time domain
# gates existed) means the embedded core does NOT inherit the root crate's
# default gate set, so each default-ON gate must be forwarded explicitly to
# keep the shipped desktop build byte-identical (AGENTS.md "Compile-time
# domain gates").
#
# This list is NOT optional polish — a gate missing here vanishes from the
# shipped app silently, with no build error and no test failure:
#
# - `voice` — without it the `#[cfg(feature = "voice")]` controllers in
# `src/core/all.rs` are never registered, so the whole `openhuman.voice_*`
# namespace answers "unknown method" at runtime. This shipped broken from
# v0.58.19 to v0.61.x (#4901); the `VOICE_COMPILED_IN` const assert at the
# top of `src/lib.rs` now fails the build if it is dropped again.
# - `media` — re-registers the `media_generate_*` agent tools that #4804 moved
# behind `#[cfg(feature = "media")]`; it sheds no deps, so this only restores
# the pre-gate desktop tool surface.
#
# `tokenjuice-treesitter` is the remaining un-forwarded default — tracked in
# #4918, deliberately not bundled here because dropping it may be intentional.
openhuman_core = { path = "../..", package = "openhuman", default-features = false, features = [
"media",
"voice",
] }
tinyjuice = { version = "0.2.1", default-features = false }

[target.'cfg(unix)'.dependencies]
Expand Down Expand Up @@ -216,7 +240,7 @@ tinyagents = { path = "../../vendor/tinyagents" }
# TinyAgents so integration work can test crate changes against OpenHuman before
# publishing.
tinyflows = { path = "../../vendor/tinyflows" }
tinycortex = { path = "../../vendor/tinycortex", features = ["git-diff"] }
tinycortex = { path = "../../vendor/tinycortex" }
tinyjuice = { path = "../../vendor/tinyjuice" }
tinychannels = { path = "../../vendor/tinychannels" }
tinyplace = { path = "../../vendor/tinyplace/sdk/rust" }
Expand Down
Loading
Loading