Skip to content

feat: add delegate pre-spawn guard - #23177

Closed
ai-ag2026 wants to merge 2 commits into
NousResearch:mainfrom
ai-ag2026:delegate-pre-spawn-guard
Closed

feat: add delegate pre-spawn guard#23177
ai-ag2026 wants to merge 2 commits into
NousResearch:mainfrom
ai-ag2026:delegate-pre-spawn-guard

Conversation

@ai-ag2026

Copy link
Copy Markdown
Contributor

Summary

Adds a disabled-by-default delegate_task pre-spawn guard so installations can call an external policy system before Hermes constructs child agents.

  • Adds delegation.pre_spawn_guard config with command-based JSON stdin/stdout protocol.
  • Blocks child construction before _build_child_agent(...) when a guard denies a planned child.
  • Uses all-or-nothing semantics for batches: if any planned child is denied, none are constructed.
  • Keeps default behavior unchanged when the guard is disabled.
  • Propagates a generic guard_context_id into delegated children so recursive delegation can stay attached to the same external work item.
  • Documents the configuration and command protocol in the delegation feature docs.

Why

Some operators need a local policy/budget/permission broker to approve subagent creation before resources are allocated or side effects become possible. The hook is generic: Hermes Core only knows about an optional guard context; integrations decide what that context means.

Example uses:

  • approval gates before autonomous subagent dispatch;
  • budget or quota checks before spawning expensive workers;
  • compliance/policy checks for enterprise deployments;
  • local project-control systems that track worker starts externally.

Design

The guard is disabled by default, and when it is disabled delegation behavior is unchanged:

delegation:
  pre_spawn_guard:
    enabled: true
    command: /usr/local/bin/permission-broker
    timeout_seconds: 3.0
    runtime_mode: manual
    fail_policy: auto
    require_task_context: false

For each planned child, Hermes sends a compact JSON payload to the command on stdin. It deliberately includes a goal_preview truncated to 240 characters, not the full task context. The command returns JSON such as:

{ "ok": true, "allowed": true, "reason": "approved" }

or:

{ "ok": true, "allowed": false, "reason": "missing approval" }

manual is for interactive sessions where an operator can react to warnings; autonomous is for unattended dispatchers where unknown states should fail closed.

allowed: false is treated as a policy decision. A valid denial should return exit 0 with allowed: false; non-zero exit, timeout, or invalid JSON are treated as hook failures and resolved by fail_policy.

Commit structure

This branch is intentionally two commits:

  1. feat: add delegate pre-spawn guard — core hook, tests, docs.
  2. feat: propagate delegate guard context to children — recursive delegation context propagation.

Test plan

python -m pytest tests/tools/test_delegate.py -q -o 'addopts='
python -m py_compile tools/delegate_tool.py tests/tools/test_delegate.py
git diff --check

Local result:

143 passed

Additional local integration smoke against an external adapter verified:

Core pre-spawn hook -> command adapter -> external guard-start
blocked path: worker_start_blocked
allowed path: worker_started

That adapter is local-only and not part of this PR.

Upstream-safety checks

Core code/tests were checked for local integration names:

grep -RInE 'tars|TARS|pm_task|tars_task_id|_tars' tools/delegate_tool.py tests/tools/test_delegate.py
# 0 matches

@alt-glitch alt-glitch added type/feature New feature or request tool/delegate Subagent delegation P3 Low — cosmetic, nice to have labels May 10, 2026
@ai-ag2026

Copy link
Copy Markdown
Contributor Author

CI follow-up after all checks completed:

Three failures appear unrelated to this PR's changed files:

  1. Windows footguns (blocking) reports tools/process_registry.py:588. This file is not modified by this PR and is byte-identical to origin/main in this branch.
  2. ruff + ty diff fails in the "Post / update PR comment" step with Resource not accessible by integration, which looks like a fork-PR comment permission issue. The blocking ruff enforcement check passed.
  3. test / e2e failures are in unrelated files that are also byte-identical to origin/main in this branch:
    • tests/gateway/test_restart_drain.py
    • tests/gateway/test_tts_media_routing.py
    • tests/hermes_cli/test_update_gateway_restart.py
    • tests/run_agent/test_async_httpx_del_neuter.py
    • tests/e2e/test_platform_commands.py

The PR diff only touches:

  • tools/delegate_tool.py
  • tests/tools/test_delegate.py
  • website/docs/user-guide/features/delegation.md

Happy to investigate further if maintainers see something specific in this PR's changes.

@ai-ag2026
ai-ag2026 marked this pull request as ready for review May 10, 2026 12:48
@ai-ag2026

Copy link
Copy Markdown
Contributor Author

Closing rather than refreshing this old branch.

The delegate pre-spawn guard is not directly replaced on current main, but nearby delegation/observability work has moved on: #29722/#29724 add subagent lifecycle observer hooks in the same tools/delegate_tool.py region and this branch now conflicts when replayed on top of them. If a policy/approval guard is still wanted, it should be re-cut later as a small fresh hook that builds on the current observer/middleware surface instead of carrying this stale branch forward.

@ai-ag2026 ai-ag2026 closed this May 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

P3 Low — cosmetic, nice to have tool/delegate Subagent delegation type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants