Skip to content

fix(openhuman): give an embedded turn a trust label and the run's checkout - #251

Merged
senamakel merged 32 commits into
tinyhumansai:mainfrom
senamakel:oh-turn-workspace
Aug 9, 2026
Merged

fix(openhuman): give an embedded turn a trust label and the run's checkout#251
senamakel merged 32 commits into
tinyhumansai:mainfrom
senamakel:oh-turn-workspace

Conversation

@senamakel

@senamakel senamakel commented Aug 8, 2026

Copy link
Copy Markdown
Member

Makes a workflow agent node dispatched to the embedded OpenHuman harness able to
do real work in the checkout the run names. Before this, a probe workflow proved the
turn was useless for coding: every write into the run's checkout was refused, and every
external-effect tool a delegated coding sub-agent tried was refused as an unlabelled
call site.

Pairs with tinyhumansai/openhuman#5452, which this PR's vendor/openhuman gitlink
moves to. That PR carries the core half and the full root-cause writeup; land it first.

Behaviour changes

run_openhuman_task now scopes two things around its
invoke("openhuman.inference_agent_chat", …) — the core's CoreRuntime::invoke polls the
handler on the calling task, so the whole turn runs inside them:

  • Origin. The turn is labelled TrustedAutomation { source: Workflow { require_approval: false }, job_id: <thread id> }. Previously the core stamped its own blanket Cli label on
    this RPC.
  • Workspace. RunTaskOptions::cwd was destructured away and never reached the turn. It
    is now resolved to a canonical directory and scoped as the turn's workspace, which makes it
    both the default cwd for acting tools and a read/write root for the core's path policy —
    so file_write into the run's checkout is no longer refused with
    Resolved parent path escapes workspace: …. An empty, missing, or non-directory cwd
    scopes nothing and leaves the turn on the core's own workspace, as today.

Also corrects stale docs: the module and run.rs claimed Medulla hooks are absent for
OpenHuman and logged a warning saying so. That has been untrue since #246 added
core_host::hooks, which registers PreToolUse/PostToolUse/Stop on the core at boot —
auto-commit really does fire during an embedded turn. The warning is removed and the module
doc now states what is actually true, including the one real difference (hooks are
process-global here, not per-dispatch).

How workflow authority reaches the turn

The origin above is keyed off a new workflowNode: true field on the task-frame
protocol, which the daemon's workflow host sets when it dispatches a graph's agent node
over its in-process loopback bridge (TaskRunnerDispatchEmbeddedDaemon). The field
alone is caller-controlled JSON, so the daemon never trusts it from a remote peer:
each transport that delivers a task frame computes its own is_device_local(from)
verdict, and that verdict is what may upgrade the frame to RunTaskOrigin::Workflow

origin: if sender_device_local && frame.workflow_node {
    RunTaskOrigin::Workflow
} else {
    RunTaskOrigin::DelegatedTask
},

A forged workflowNode: true from any authenticated peer over the host link is therefore
read as ordinary delegated work, so the TrustedAutomation::Workflow label — and the
require_approval: false it carries — is only ever minted by daemon-local dispatch the
operator's own workflow store drove. The loopback workflow host is the sole legitimate
producer and it resolves device-local, so unattended workflow nodes keep their authority.

Policy / security implication

Labelling these turns TrustedAutomation::Workflow { require_approval: false } means the
approval gate auto-allows external-effect tools for them instead of parking for a human
decision. This is the same trust root a user-authored cron job's prompt carries, and the same
one a saved tinyflows workflow already gets: the graph was authored and saved by the operator
before it ran, so the action is pre-declared. Parking instead would strand an unattended run
on a prompt nobody is watching. The turn's own id rides on job_id, so an audit row or a
parked approval names the dispatch it came from. Because the label can only be minted by
device-local dispatch (see above), this trust root is not reachable by any peer that can
authenticate to a remote host.

The workspace grant is deliberately no stronger than a user-configured
TrustedRoot { access: ReadWrite } — credential stores, workspace-internal state, and the
cross-profile write guard are all unaffected. See the openhuman PR for the detail.

Two origins are explicitly not workflow-labelled:

  • Evolution-pass reviews (task_loop/workflow/handle.rs). An auto-on-failure
    review turn runs proposal tools against a failed run; it is not an authored workflow
    node, so its RuntimeDispatch is pinned to RunTaskOrigin::DelegatedTask and never
    inherits the trust label.
  • Remote delegated tasks of any kind. Only the sender_device_local gate above may
    produce Workflow, and a host-link peer is never device-local.

Hook execution semantics

While correcting the docs, the hook runner also changed one behaviour: a hook whose
stdin payload cannot be written (the command closed its stdin, or exited first) is now
captured in the wait result and only surfaced when the hook is enforced. Before, a
write error short-circuited the async block and failed the call even for observational
stop hooks. A pre-hook (enforce_status = true) that never received its payload still
vetoes the tool call; a stop hook (enforce_status = false) absorbs the write failure,
because that race — the hook closing stdin before the payload lands — must not fail the
turn.

Validation

From this worktree:

  • cargo fmt --check — clean
  • cargo clippy --all-targets -- -D warnings — clean
  • cargo test — all suites pass (2620 + 1062 + … , 0 failed)

And in vendor/openhuman (see #5452 for the full list): cargo fmt --check,
cargo clippy --lib -- -D warnings, and the turn_origin / turn_workspace / turn_root /
effective_origin / security::policy / orchestration / session::builder suites.

New unit tests cover: the cwd resolution branches (unset, missing, a file, and a
non-canonical path that must resolve to the canonical root); the workflowNode origin
gate (a forged marker from a remote sender is demoted to DelegatedTask, a device-local
sender keeps Workflow, and a device-local sender without the marker stays
DelegatedTask); and the hook stdin-write race (an enforced hook whose payload cannot
be written vetoes, while an observational stop hook absorbs the write failure).

senamakel and others added 9 commits August 8, 2026 18:01
Adds the openhuman library as a vendored dependency to support upcoming functionality that relies on its APIs.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The OpenHuman provider now treats a missing run id as an error instead of silently proceeding, which prevents downstream failures when the provider returns an incomplete response.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The OpenHuman provider now treats a missing run id as an error instead of silently proceeding, preventing downstream failures when the provider returns an incomplete response.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The OpenHuman provider now treats a missing run id as an error instead of silently proceeding, which prevents downstream failures caused by an invalid or incomplete provider response.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The OpenHuman provider now treats a missing run id as an error instead of silently proceeding, which prevents downstream failures when the provider returns an incomplete response.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Refresh the vendored openhuman crate to its latest upstream revision, incorporating upstream fixes and improvements. No local code changes were required beyond the vendor update.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The OpenHuman provider now treats a missing run id as an error instead of panicking, ensuring graceful failure when the API returns an unexpected payload.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Add tests for the turn workspace root helper, covering unset, missing, and non-directory paths to ensure they grant no root, and verifying that existing checkouts resolve to canonical absolute paths for containment checks.

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

coderabbitai Bot commented Aug 8, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@senamakel, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 41 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: e32e7ffd-dc3e-4907-919c-7abd00ec5da5

📥 Commits

Reviewing files that changed from the base of the PR and between 37f2b0c and ed4fac3.

📒 Files selected for processing (41)
  • src/sdk/src/core_host/hooks.rs
  • src/sdk/src/core_host/hooks_tests.rs
  • src/sdk/src/core_host/shared.rs
  • src/sdk/src/daemon/capabilities/mod.rs
  • src/sdk/src/daemon/embedded/mod.rs
  • src/sdk/src/daemon/entry.rs
  • src/sdk/src/daemon/providers/acp/tests/execution.rs
  • src/sdk/src/daemon/providers/codex_server/tests.rs
  • src/sdk/src/daemon/providers/mod.rs
  • src/sdk/src/daemon/providers/openhuman/mod.rs
  • src/sdk/src/daemon/providers/openhuman/run.rs
  • src/sdk/src/daemon/providers/openhuman/tests.rs
  • src/sdk/src/daemon/providers/tests.rs
  • src/sdk/src/daemon/providers/types.rs
  • src/sdk/src/daemon/runtime.rs
  • src/sdk/src/daemon/task_loop/mod.rs
  • src/sdk/src/daemon/task_loop/run.rs
  • src/sdk/src/daemon/task_loop/workflow/dispatch.rs
  • src/sdk/src/daemon/task_loop/workflow/handle.rs
  • src/sdk/src/daemon/tests/mod.rs
  • src/sdk/src/daemon/tests/origin_tests.rs
  • src/sdk/src/flow_engine/caps/dispatch.rs
  • src/sdk/src/hub/runner/mod.rs
  • src/sdk/src/protocol/frames/decode.rs
  • src/sdk/src/protocol/frames/encode.rs
  • src/sdk/src/protocol/frames/mod.rs
  • src/sdk/src/protocol/frames/tests/codec.rs
  • src/sdk/src/protocol/frames/types.rs
  • src/sdk/src/protocol/mod.rs
  • src/sdk/src/sessions/manager/turns.rs
  • src/sdk/src/sessions/tests/input_tests.rs
  • src/sdk/tests/e2e_codex_app_server.rs
  • src/sdk/tests/e2e_daemon/helpers.rs
  • src/sdk/tests/e2e_daemon_providers.rs
  • src/sdk/tests/e2e_daemon_router.rs
  • src/tui/src/local_host/tests/dispatch.rs
  • src/tui/src/worker/executor_tests/live.rs
  • src/tui/src/worker/executor_tests/mod.rs
  • src/tui/src/worker_loop/mod.rs
  • src/tui/tests/e2e_session_takeover.rs
  • vendor/openhuman

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.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ffa68b785e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/sdk/src/daemon/providers/openhuman/run.rs Outdated
Comment thread src/sdk/src/daemon/providers/openhuman/mod.rs
Comment thread src/sdk/src/daemon/providers/openhuman/run.rs Outdated
@senamakel senamakel self-assigned this Aug 8, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f2f11259b7

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/sdk/src/core_host/shared.rs

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 33eaf49eec

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/sdk/src/daemon/task_loop/workflow/dispatch.rs Outdated
Comment thread src/sdk/src/daemon/task_loop/run.rs Outdated
# Conflicts:
#	src/sdk/src/daemon/providers/openhuman/run.rs
#	src/sdk/src/daemon/providers/openhuman/tests.rs

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 70da5749c3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/sdk/src/daemon/task_loop/run.rs Outdated
senamakel and others added 8 commits August 9, 2026 16:08
The runtime previously failed to signal the daemon to shut down when the last handle was dropped, leaving the daemon running indefinitely. This change restores the shutdown signal so the daemon exits cleanly once all runtime handles are released.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The task loop now checks for a shutdown signal before processing each iteration, ensuring the daemon exits promptly when a termination request is received rather than continuing to run until the next natural break point.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The task loop run module is no longer needed as its functionality has been superseded by the updated task scheduling logic. This change removes the dead code to keep the codebase clean and reduce maintenance overhead.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
When the task loop's receiver channel is closed, the loop now exits cleanly instead of panicking. This ensures graceful shutdown when the sender is dropped, preventing unnecessary error logs and improving daemon stability during normal termination.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
When the daemon binary path is not set, the embedded daemon now returns an error instead of panicking. This improves robustness by allowing callers to handle the missing configuration explicitly rather than crashing unexpectedly.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
When the daemon starts, it now checks for the presence of a required entry field and logs a clear error if it is missing, preventing a silent failure or panic later in the startup sequence.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The daemon entry point previously dropped the shutdown signal handler, causing the process to exit immediately instead of waiting for a termination signal. This change retains the handler so the daemon runs until explicitly stopped.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The worker loop now gracefully handles the case where a file being watched is deleted before the watcher processes it, preventing a panic from an unwrap on a missing entry.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
senamakel and others added 7 commits August 9, 2026 16:14
Adds test coverage for the origin module in the SDK daemon, verifying that origin-related functionality behaves as expected. This ensures the daemon's origin handling is properly validated and guarded against regressions.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The origin tests were previously removed during a refactor, and this change restores them to ensure the daemon's origin handling behavior is properly verified. The tests cover the expected origin validation and rejection paths.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The test module declaration in the daemon tests file was updated to use the correct module path, ensuring that the tests are properly discovered and executed by the test runner. This fixes a broken test configuration that previously prevented the daemon tests from running.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The origin tests were previously removed during a refactor, and this change restores them to ensure the origin resolution logic remains verified. The tests cover the expected behavior of origin handling in the daemon.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The origin test that verifies the daemon's absence was previously removed, and this change restores it to ensure the expected behavior is covered again.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Reformatted several multi-line function calls and import statements to fit on single lines, and fixed a missing trailing newline in a test file. These changes are purely cosmetic and do not affect any runtime behaviour.

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

@tinysweeper tinysweeper Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Requesting changes: 1 lane(s) blocking, worst finding is high.

Fix or reply to the findings below and push. The next review clears this automatically once they are gone — you should not need to dismiss anything by hand.

             $0.0099 · 148,204 in / 27,514 out · 115,077 cached (78%) · z-ai/glm-5.2
critique:    $0.0029 · 33,401 in  / 6,509 out  · 14,598 cached (44%)  · z-ai/glm-5.2
security:    $0.0044 · 79,277 in  / 12,628 out · 69,568 cached (88%)  · z-ai/glm-5.2
tests:       $0.0014 · 17,536 in  / 4,815 out  · 15,080 cached (86%)  · z-ai/glm-5.2
description: $0.0011 · 17,990 in  / 3,562 out  · 15,831 cached (88%)  · z-ai/glm-5.2

Comment thread src/sdk/src/core_host/hooks.rs
Comment thread src/sdk/src/daemon/task_loop/run.rs
Comment thread src/sdk/src/core_host/hooks.rs
Comment thread src/sdk/src/daemon/task_loop/workflow/handle.rs
@tinysweeper tinysweeper Bot added priority: p1 Next. Wrong behaviour a user will hit, or a security weakness behind a condition. severity: high labels Aug 9, 2026
senamakel and others added 2 commits August 9, 2026 16:51
The test that verifies provider creation fails when the daemon is absent was previously removed. This change restores it to ensure the error path is covered again.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Corrected a misspelled word in a comment within the hooks test file to improve readability and maintain consistency with the codebase's documentation standards.

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

@tinysweeper tinysweeper Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The previously-blocking findings are resolved. Clearing the changes request.

             $0.0030 · 55,967 in / 8,704 out · 49,611 cached (89%) · z-ai/glm-5.2
critique:    $0.0007 · 17,542 in / 1,608 out · 15,787 cached (90%) · z-ai/glm-5.2
security:    $0.0003 · 2,129 in  / 1,200 out · 1,894 cached (89%)  · z-ai/glm-5.2
tests:       $0.0008 · 17,921 in / 2,016 out · 16,128 cached (90%) · z-ai/glm-5.2
description: $0.0012 · 18,375 in / 3,880 out · 15,802 cached (86%) · z-ai/glm-5.2

Comment thread src/sdk/src/daemon/task_loop/run.rs
Comment thread src/sdk/src/core_host/hooks.rs
@tinysweeper tinysweeper Bot added priority: p2 Soon. Real but survivable — a rough edge, a gap, a thing that will bite later. severity: medium priority: p3 Whenever. Cosmetic, a nicety, or a cleanup with no user visible effect. and removed priority: p1 Next. Wrong behaviour a user will hit, or a security weakness behind a condition. severity: high priority: p2 Soon. Real but survivable — a rough edge, a gap, a thing that will bite later. labels Aug 9, 2026
@senamakel
senamakel merged commit a44315d into tinyhumansai:main Aug 9, 2026
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

priority: p3 Whenever. Cosmetic, a nicety, or a cleanup with no user visible effect. severity: medium

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant