Skip to content

refactor(core_host): port the embedded core onto openhuman_core::Harness - #278

Draft
senamakel wants to merge 37 commits into
tinyhumansai:mainfrom
senamakel:embed-harness
Draft

refactor(core_host): port the embedded core onto openhuman_core::Harness#278
senamakel wants to merge 37 commits into
tinyhumansai:mainfrom
senamakel:embed-harness

Conversation

@senamakel

Copy link
Copy Markdown
Member

Draft — blocked on tinyhumansai/openhuman#5668.
This branch's vendor/openhuman gitlink points at a commit that only exists on that PR's branch, so submodule init cannot resolve it from the canonical repo and CI will fail to fetch. Before this is ready: #5668 merges → re-point vendor/openhuman at the resulting main commit → mark ready for review.

Summary

  • Ports the embedded-core host onto openhuman_core::Harness and the new typed embed::Core::agent() / auth() facades from openhuman#5668.
  • Deletes core_host/auth.rs and its tests (222 lines). Every caller uses core.auth(); medulla's private AuthState projection becomes a re-export of the core's.
  • Removes all four std::env::set_var calls that configured the core. CoreSettings::resolve(env, config, home) returns a value; boot(settings) takes it.
  • Replaces the hand-built turn JSON with harness.turn(..).session(..).cwd(..).model(..).route(..).origin(..).on_progress(..).send(), deleting reply_text and scoped_origin along with both private copies of the RpcOutcome envelope heuristic.
  • Bumps vendor/openhuman by 1047 commits (v0.63.7-era → v0.63.17 + #5668), with the manifest and API updates that requires.

Net on the ported files: −854 / +553 lines.

Problem

Running one agent turn through the embedded core took ~2,100 lines of glue across 17 ordered steps, and the sharp edges were all in this repo's own comments:

  • Four std::env::set_var calls, sequenced before a constructor they do not appear in, replicated at six call sites. Process-global, inherited by every child, and increasingly hostile in newer Rust editions.
  • execution.rs:240 documented that AgentChatParams carries no rename_all, so the hand-built params depended on an unmarked naming coincidence — an upstream rename would fail silently at runtime.
  • Two divergent copies of the {result, logs} envelope unwrapper (auth.rs strict, execution.rs loose).
  • A private AuthState mirror of the core's response, decoded by hand out of that envelope.
  • core_host/tests.rs needed a process-wide mutex and had to clear four environment variables around every case, because the functions under test wrote to the environment.

Solution

Settings are values, not environment variables. CoreSettings { workspace, action_dir, backend_url } is resolved once and handed to boot. The precedence is unchanged and still ours — an operator who exported OPENHUMAN_WORKSPACE still wins — but it is a parameter now instead of a convention about call ordering.

One nuance worth reviewing: the lazy boot path genuinely has no caller to hand settings to (a workflow agent node runs deep inside the engine, and the dispatch signature belongs to every harness). That is replaced by a typed OnceLock<CoreSettings> in core_host. Still process-global — same problem — but the blast radius changes: a cell this crate owns affects this process's core, where OPENHUMAN_WORKSPACE affected every library in the process and every child it spawned.

The TUI still writes those variables into its child-process env snapshot, and should: OpenHuman's picker entry and the harness CLIs are spawned processes. What changed is that we no longer mutate this process's environment to talk to a library living inside it. backend_url also collapses two bindings into one — with no OPENHUMAN_MEDULLA_BASE_URL override, the core's Medulla client falls through to the same api_url.

Two things deliberately not folded in:

  • with_turn_cwd is still scoped by hand. It is read by Medulla's process-global lifecycle hooks, not by the core, so there is nothing upstream that could take it as an argument.
  • boot_for_auth keeps using CoreBuilder rather than Harness. It is a short-lived core for one question, and claiming the process's single harness slot for it would refuse a later real boot in the same process.

The vendor bump is unrelated churn but unavoidable, since the new API lives upstream. It cost:

Change Why
tinyflows 0.60.8 vendored engine version
new [patch."https://github.com/tinyhumansai/tinymemory"] mirrors openhuman's own; without it tinymemory-api resolves as both a git copy (via tinycortex) and a path copy, producing a wall of E0308s about two MemoryTaint types
dropped stale tinyjuice patch that vendor directory no longer exists
6 new NodeKind variants covered in 4 matches Spawn/Scatter/Gather/Gate/Approval/Void
2 new Capabilities fields tasks set to the engine's TokioTaskRunner so spawn/gate genuinely overlap; approvals: None until we have a review surface to push at
5 new SDK socket error variants listed by name, not swept into a catch-all, so a future variant is a compile error

Commit history is the auto-commit hook's granular checkpoints, left as-is rather than squashed.

Impact

  • Behaviour: no intended change. Same precedence, same presets (DomainSet::embedded() / ServiceSet::embedded()), same one-core-per-process rule — now enforced from both sides, since Harness::build returns AlreadyRunning rather than silently sharing process-global state.
  • Testing: core_host/tests.rs went 295 → 189 lines and lost its environment mutex entirely — the cases are independent values now and run in parallel. That the lock could be deleted is the point of the change, not a side effect.
  • Risk: the vendor bump is the larger half of this diff and touches workflow-graph rendering and SDK error mapping. Both are covered by the existing suite.

Validation

  • cargo test --workspace70 test binaries, 0 failures
  • cargo clippy --workspace --all-targets — clean
  • cargo fmt --all --check — clean
  • Baseline confirmed green at the pre-bump pin before any change, so every error resolved here was attributable.

Related

senamakel and others added 30 commits August 21, 2026 22:59
Updated the pinned commit of the openhuman vendored dependency to include the latest upstream changes.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Update the tinyflows dependency to version 0.8 while keeping the "mock" feature enabled, picking up the latest bug fixes and improvements from the upstream crate.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Updated the Cargo.lock file to reflect changes in dependencies, ensuring the lockfile remains in sync with the current Cargo.toml.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
…ate conflict

The vendored tinycortex depends on tinymemory-api via a git URL, which caused Cargo to resolve it as a separate crate from the path copy in the vendor tree, producing type mismatch errors. This patch mirrors the entry from openhuman's own manifest, rebased onto the vendor path structure, to ensure both references resolve to the same crate. Also removes the stale tinyjuice entry.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Removed the duplicate git-sourced entry for tinymemory-api 0.1.1 and replaced all references to it with the local version, eliminating the need for a separate patched dependency. Also removed an unused patch entry for tinyjuice.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
When resolving a hostname, the code now checks for a missing host field and returns an appropriate error instead of panicking or producing an incorrect result. This ensures robust behavior when the host field is absent from the configuration.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
When the hostname field is absent from the host info response, the SDK now returns an empty string instead of failing to parse the response. This ensures compatibility with hosts that do not provide a hostname.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
When the hostname field is absent from the host info response, the SDK now returns an empty string instead of failing to parse the response. This prevents a crash when connecting to hosts that do not provide a hostname.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Update the openhuman vendor dependency to a newer version that includes a fix for a host-side crash when processing malformed input packets. The previous version did not properly validate packet boundaries, which could lead to a buffer over-read under certain conditions.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Add a fallback for when the hostname field is absent in the shared host context, defaulting to an empty string instead of failing. This prevents crashes in environments where the hostname is not provided.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
When resolving a hostname, the code now correctly handles the case where no host is present in the URI, preventing a panic that occurred when attempting to unwrap an empty host string.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Replaced the separate `bind_from_config`, `bind_workspace`, and `bind_action_dir` calls with a single `CoreSettings` struct that is resolved and installed atomically. This makes the core's configuration path explicit and consistent across the MCP server and local workflow host, and the first-writer-wins semantics prevent a late startup from overwriting settings that a more complete path already published.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Add a TokioTaskRunner to the capabilities builder so that spawn nodes run concurrently with their collecting gates, and set approvals to None with a comment explaining that the feature works through the existing resume mechanism even though the push surface is not yet implemented.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
…iew node kinds

Extend the graph rendering helpers to support the new node kinds introduced in tinyflows 0.8. The wire names use the enum's snake_case serde spelling so they match what a saved document carries, the glyphs use arrows and symbols that convey the direction of branching or the need for human interaction, and the colour assignments keep concurrency nodes in the yellow control-flow group while placing the approval node in green alongside the entry point.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Add explicit arms for Socket.IO transport failures in the `From<tinyhumans_sdk::Error>` implementation for `ClientError`, mapping them to `ClientError::Api` with no status or error code. This ensures that connection-level failures are reported as transport issues rather than API refusals, and that any future socket variant will cause a compile error until deliberately classified.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Adds descriptive fallback text for spawn, scatter, gather, gate, approval, and void nodes in the node summary function. Each node kind now returns a meaningful label that captures its purpose, such as "ticket" for spawns or "items" for scatters, making the graph more informative at a glance.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The turn construction is migrated from a `serde_json::json!` literal and
task-local scopes to a typed builder on the harness, which owns the contract
with `AgentChatParams` and eliminates silent runtime failures from field name
mismatches. The origin scope and progress sink are now composed through the
builder rather than as separate wrappers, and the ad-hoc `reply_text` helper is
removed in favour of a structured `reply` field on the outcome.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Renamed the variable `core` to `harness` in the OpenHuman task execution function to better reflect that the value returned by `shared_with_hooks` is a harness rather than a core instance, improving code readability and reducing confusion about the variable's purpose.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Convert the error to a string before emitting it to the sink, ensuring the error message is consistently reported as a sentence across all harnesses. This avoids callers needing to know which harness produced the error, as `CoreError`'s `Display` already provides the method and domain message that operators read.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
…ngs value

Replace four separate `std::env::set_var` calls and their associated binding functions with a single `CoreSettings` value that is resolved once and then installed for the embedded core. This eliminates the mutation of the current process's environment to configure an in-process library, keeping environment variables only for the child-process snapshot where they are genuinely needed.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The app loop now accesses authentication through the core's typed facade instead of free functions, and the boot process returns a harness that owns the core's lifetime. This simplifies the ownership model by keeping the harness alive while allowing the core to be cloned for shared use, and makes the auth API consistent across the codebase.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The login flow now extracts a harness from the pending core and clones the core from it, ensuring the shared install and runtime use the harness wrapper instead of the raw core. This preserves the harness context needed for proper lifecycle management during the sign-in process.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Re-exports `Session` and `Harness` from the core host module so that workspace crates like the TUI can reference them without a direct dependency on the `openhuman` crate, matching the existing pattern used for `AuthState`. The TUI call site is updated to use the new re-exported path.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Replace the pattern of binding individual environment variables for workspace, action directory, and API URLs with a single `CoreSettings::resolve` call that produces a settings object passed directly to `boot_for_auth` and `boot_with_hooks`. This eliminates the risk of mismatched bindings when the same configuration is used across multiple call sites, and makes the settings flow explicit rather than relying on ambient environment variables.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The `Harness` type was imported but never used in the module, causing a compiler warning. Removing it cleans up the unused import.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
… relogin

The `AuthState` type was previously accessed through the nested `medulla::core_host::auth` module path, but has been re-exported at the `medulla::core_host` level. All references across the TUI crate and its tests are updated to use the shorter path. In the relogin flow, the harness now wraps the core in an `Arc` before passing it to the relogin function, ensuring the core's lifetime is properly managed by the harness.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Removed the hand-written `core_host::auth` module that wrapped the core's auth RPCs through `Core::raw`, and replaced all call sites with the new typed `core.auth()` facade. The old module existed as a bridge until the upstream core exposed a proper typed auth surface; that surface now exists, so the bridge is no longer needed.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
…on functions

The workspace, action directory, and backend URL functions no longer write to the process environment; they return a `CoreSettings` struct instead. This removes the global mutex that serialised the test suite and lets every test case run in parallel. The old `bind_from_config` and `classify` helpers are replaced by `CoreSettings::resolve` and `CoreSettings::floor`, and the Medulla readiness classification tests were removed because they tested a function that no longer exists.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The `reply_text` function was re-exported from the run module under a `#[cfg(test)]` guard, but the only consumer was the test module itself, which imported it directly from the sibling module. Removing the conditional re-export eliminates a dead-code warning in non-test builds without affecting test coverage.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
senamakel and others added 7 commits August 21, 2026 23:39
Reformat several chained method calls across the SDK and TUI to place each call on its own line, improving readability and aligning with the project's established style. Also collapse a multi-line function signature in `resolve_action_dir` to a single line for consistency with nearby declarations.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The variable `workspace_roots` was computed from the loaded configuration but never used anywhere in the application loop, so it has been removed to eliminate dead code and reduce unnecessary allocations.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The re-export of `with_progress_sink` from `core_contract.rs` was removed because it is no longer needed by external consumers, and the unused `serde_json::json` import was removed from the test file to eliminate a compiler warning.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
…ess` pattern

The module documentation for `with_progress_sink` was outdated: the sink is now passed as an argument to `Turn::on_progress` rather than scoped by hand via a `tokio::task_local`. The doc block is updated to explain that the provider no longer needs to know about the scoping mechanism, and to clarify that `with_turn_cwd` remains manually scoped because it is read by Medulla's lifecycle hooks rather than by the core.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Updated the pinned commit for the openhuman subproject to include the latest changes from its upstream repository.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Removed an unnecessary blank line between the use statements in the test file to improve code consistency and readability.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Updated the pinned commit for the openhuman vendored subproject to include the latest upstream changes.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
@coderabbitai

coderabbitai Bot commented Aug 21, 2026

Copy link
Copy Markdown

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: dde8a94d-1091-4140-94a7-969fd30ead53

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant