Skip to content

feat(hermes): request network access through policy local#3748

Open
cheese-head wants to merge 6 commits into
NVIDIA:mainfrom
cheese-head:policy-access/hermes-network-tool
Open

feat(hermes): request network access through policy local#3748
cheese-head wants to merge 6 commits into
NVIDIA:mainfrom
cheese-head:policy-access/hermes-network-tool

Conversation

@cheese-head

@cheese-head cheese-head commented May 18, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds a Hermes plugin tool for OpenShell policy.local network access requests. Hermes exposes the single openshell_network_access tool with list_presets, request, and check actions, matching the no-legacy-alias tool contract.

Changes

  • Add provider-profile backed preset discovery and policy.local proposal handling to agents/hermes/plugin/__init__.py.
  • Register openshell_network_access in the Hermes plugin manifest.
  • Add Hermes unit coverage for tool registration, proposal submission, validation, and status mapping.
  • Add live e2e helper scripts for the Hermes policy.local flow.
  • Update the integration reference to describe the Hermes operation-dispatched tool shape.

Type of Change

  • Code change (feature, bug fix, or refactor)
  • Code change with doc updates
  • Doc only (prose changes, no code sample modifications)
  • Doc only (includes code sample changes)

Verification

  • npx prek run --all-files passes
  • npm test passes
  • Tests added or updated for new or changed behavior
  • No secrets, API keys, or credentials committed
  • Docs updated for user-facing behavior changes
  • make docs builds without warnings (doc changes only)
  • Doc pages follow the style guide (doc changes only)
  • New doc pages include SPDX header and frontmatter (new pages only)

Signed-off-by: Patrick Riel priel@nvidia.com

Summary by CodeRabbit

Release Notes

  • New Features

    • OpenShell resource access request workflow: submit access proposals, wait for operator approval, check request status.
    • Added 10+ new provider profiles including Discord, Slack, Telegram, PyPI, npm, Jira, HuggingFace, Brave Search, Homebrew, and local inference.
  • Enhancements

    • GitHub access preset now supports gh CLI and includes Node/curl binaries.
    • Docker images include GitHub and GitLab CLI tools.
    • Provider profiles automatically imported during onboarding.
  • Documentation

    • Added NemoClaw OpenShell integration guide.

Review Change Stack

@copy-pr-bot

copy-pr-bot Bot commented May 18, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@coderabbitai

coderabbitai Bot commented May 18, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

This PR adds OpenShell "network-only" resource access support to NemoClaw and Hermes plugins. It introduces an access client for policy.local HTTP communication, provider profile integration into the policy system, onboarding synchronization with OpenShell, tool registration in both plugins, nine new provider profiles, and comprehensive Docker/build/test infrastructure.

Changes

OpenShell Network Access Integration

Layer / File(s) Summary
Access client core: HTTP and preset management
nemoclaw/src/access-client.ts, nemoclaw/src/access-client.test.ts
New access-client module defines request/response types, built-in presets, provider-profile ingestion from OpenShell, HTTP communication with policy.local endpoint (including chunked decoding and proxy support), preset caching, and exported functions for proposal creation, status checking, and waiting.
Policy preset merging and provider profile conversion
src/lib/policy/index.ts, test/policies.test.ts
listPresets() and loadPreset() now incorporate OpenShell provider profiles: reads profiles from OpenShell CLI or environment JSON, converts to policy-compatible YAML presets, merges with built-in presets, and exports helper functions for external use.
Provider profile onboarding and synchronization
src/lib/onboard/provider-profiles.ts, src/lib/onboard.ts, test/provider-profile-onboard.test.ts
New ensureNemoClawProviderProfiles() function syncs bundled NemoClaw profiles with OpenShell: lists existing, identifies missing, runs lint/import, handles unsupported subcommands with fallback messaging, and cleans up temporary directories.
NemoClaw OpenClaw plugin resource access tools
nemoclaw/src/index.ts, nemoclaw/src/register.test.ts
Registers three OpenClaw tools via new registerTool() API: request_resource_access (create and wait for approval), list_resource_access_presets (enumerate presets), check_resource_access (poll status), including resource normalization and timeout clamping.
Hermes plugin network access tools
agents/hermes/plugin/__init__.py, agents/hermes/plugin/plugin.yaml, test/hermes-plugin-handlers.test.ts
Adds openshell_network_access tool with list_presets, check, and request actions; implements provider-profile preset loading, raw HTTP policy.local communication, and proposal submission/polling logic specific to Hermes Python plugin.
Provider profile definitions and preset updates
nemoclaw-blueprint/provider-profiles/*, nemoclaw-blueprint/policies/presets/github.yaml
Introduces nine new OpenShell provider profiles (brave, brew, discord, huggingface, jira, local-inference, npm, pypi, slack, telegram) defining network endpoints, access rules, and required binaries; expands GitHub preset to include gh, glab, curl, and node tools.
Docker and build infrastructure for provider tools
scripts/install-provider-tools.sh, Dockerfile, Dockerfile.base, scripts/generate-openclaw-config.py, src/lib/sandbox/build-context.ts, test/sandbox-build-context.test.ts, test/generate-openclaw-config.test.ts
New install-provider-tools.sh script installs missing Debian/npm packages (gh, glab, jq, claude, codex, opencode) and creates copilot wrapper; Docker images copy and execute the script; build system stages the script and initializes config.json with valid JSON; OpenClaw plugin is loaded by default.
Configuration loading robustness
nemoclaw/src/onboard/config.ts, nemoclaw/src/onboard/config.test.ts
loadOnboardConfig() now handles empty files and malformed JSON gracefully: reads trimmed content, returns null for empty/whitespace, catches JSON.parse errors instead of throwing.
End-to-end test runners and harness
test/e2e/nemoclaw-policy-local-runner.mjs, test/e2e/hermes-policy-local-runner.py, test/e2e/test-nemoclaw-policy-local-plugin.sh, test/e2e/test-hermes-policy-local-plugin.sh
Adds executable E2E runners and test scripts: Node.js and Python runners register plugins locally and dispatch CLI commands; Bash test scripts provision sandboxes, upload artifacts, wait for SSH connectivity, and validate list/request/approve/check flows over SSH.
Integration documentation
docs/reference/nemoclaw-openshell-integration.md
New reference document describing the OpenShell integration flow (agent → adapter → proposals → operator review → policy reload), tool operations, adapter contract, and onboarding semantics with idempotency and fallback behavior.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Suggested labels

Sandbox

Suggested reviewers

  • ericksoa

Poem

🐰 Hops with glee through policy lands,
Provider profiles in eager hands,
GitHub, PyPI, Discord flow,
Approvals granted, access bestow!
Sandbox tools dance in harmony true, 🎭

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 5.77% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(hermes): request network access through policy local' clearly and concisely describes the main feature added: enabling Hermes to request network access through the policy.local mechanism.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
⚔️ Resolve merge conflicts
  • Resolve merge conflict in branch policy-access/hermes-network-tool

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint skipped: no ESLint configuration detected in root package.json. To enable, add eslint to devDependencies.


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

@wscurran wscurran added enhancement: policy integration: hermes Hermes integration behavior labels May 18, 2026
@wscurran

Copy link
Copy Markdown
Contributor

✨ Thanks for submitting this detailed PR to add a Hermes plugin for OpenShell policy.local network access requests. This change aims to improve the integration of Hermes with OpenShell by exposing a new tool for requesting network access and handling policy.local proposals.

@cheese-head cheese-head marked this pull request as ready for review May 21, 2026 19:21

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (8)
docs/reference/nemoclaw-openshell-integration.md (4)

1-3: ⚡ Quick win

Add a brief intro paragraph immediately after the H1.

The page currently starts with a diagram; add a one- or two-sentence introduction first.

As per coding guidelines, a new docs page should "start with a one- or two-sentence introduction."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/reference/nemoclaw-openshell-integration.md` around lines 1 - 3, Add a
one- or two-sentence introduction immediately after the H1 "NemoClaw OpenShell
Integration" and before the opening ```mermaid block; the intro should briefly
state the purpose of the page (what the integration covers and who it’s for) so
the document starts with the required summary sentence(s) prior to the diagram.

76-76: ⚡ Quick win

Split this into one sentence per source line.

Line 76 contains multiple sentences on one line, which breaks docs diff/readability rules.

As per coding guidelines, "One sentence per line in source (makes diffs readable)."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/reference/nemoclaw-openshell-integration.md` at line 76, The line
containing "Each agent adapter exposes the same response shape through the
harness-native mechanism. OpenClaw uses its plugin API. Hermes uses its Python
plugin API. Additional harnesses can implement the same proposal flow without
changing the OpenShell policy API." must be split so each sentence is on its own
source line; edit that paragraph to place each of the four sentences ("Each
agent adapter exposes...", "OpenClaw uses its plugin API.", "Hermes uses its
Python plugin API.", "Additional harnesses can implement...") on separate lines
to satisfy the one-sentence-per-line docs rule.

78-81: ⚡ Quick win

Add a terminal “Next Steps” section with related links.

The page ends without the required closing navigation section.

As per coding guidelines, new docs pages require 'A "Next Steps" section at the bottom links to related pages.'

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/reference/nemoclaw-openshell-integration.md` around lines 78 - 81, Add a
terminal "Next Steps" section to the docs page that provides links to related
pages and closes the navigation block; specifically, after the "## Provider
Profiles" content add a new "## Next Steps" heading followed by a short bullet
or link list to related docs (e.g., onboarding, policy presets, gateway
integration) and ensure any required closing navigation markup is present so the
page meets the docs guideline for a terminal navigation section.

80-80: ⚡ Quick win

Rewrite passive constructions in active voice and split sentences by line.

This line uses passive phrasing (e.g., “are left untouched”, “are skipped”) and packs multiple sentences into one line.

As per coding guidelines, "Active voice required. Flag passive constructions." and "One sentence per line in source."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/reference/nemoclaw-openshell-integration.md` at line 80, Replace the
single passive sentence starting "NemoClaw imports OpenShell provider
profiles..." with multiple active-voice sentences: keep the first sentence as
"NemoClaw imports OpenShell provider profiles for its policy presets during
onboarding," add a second active sentence like "NemoClaw leaves existing
OpenShell profiles unchanged," a third like "NemoClaw skips profiles it already
imported so onboarding is idempotent," and a final sentence for the fallback:
"If the OpenShell gateway does not support provider-profile import, NemoClaw
falls back to local presets." Ensure each sentence is on its own line and update
the exact sentence block in docs/reference/nemoclaw-openshell-integration.md.
src/lib/onboard.ts (1)

9751-9751: Run the onboarding E2E matrix for this flow change.

Since this hook now executes in the core onboarding path, please run the recommended jobs for src/lib/onboard.ts changes (cloud-e2e, sandbox-operations-e2e, rebuild-openclaw-e2e, channels-stop-start-e2e, messaging-compatible-endpoint-e2e, hermes-discord-e2e, hermes-slack-e2e, openshell-gateway-upgrade-e2e).

As per coding guidelines: src/lib/onboard.ts changes should be validated with the listed onboarding E2E workflows.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/lib/onboard.ts` at line 9751, This change adds
ensureProviderProfilesAvailable() into the core onboarding path in
src/lib/onboard.ts; run the full onboarding E2E matrix to validate it by
executing the required jobs: cloud-e2e, sandbox-operations-e2e,
rebuild-openclaw-e2e, channels-stop-start-e2e,
messaging-compatible-endpoint-e2e, hermes-discord-e2e, hermes-slack-e2e, and
openshell-gateway-upgrade-e2e to ensure no regressions when
ensureProviderProfilesAvailable() runs during onboarding.
nemoclaw/src/onboard/config.test.ts (1)

146-156: ⚡ Quick win

Add a whitespace-only config test case.

Line 146 covers empty content, but loadOnboardConfig() also trims input first. Please add a case like " \n\t " to assert that whitespace-only files also return null.

Proposed test addition
   it("returns null when the config file is empty", () => {
     const configPath = `${homedir()}/.nemoclaw/config.json`;
     store.set(configPath, "");
     expect(loadOnboardConfig()).toBeNull();
   });

+  it("returns null when the config file contains only whitespace", () => {
+    const configPath = `${homedir()}/.nemoclaw/config.json`;
+    store.set(configPath, "  \n\t  ");
+    expect(loadOnboardConfig()).toBeNull();
+  });
+
   it("returns null when the config file is malformed", () => {
     const configPath = `${homedir()}/.nemoclaw/config.json`;
     store.set(configPath, "{");
     expect(loadOnboardConfig()).toBeNull();
   });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@nemoclaw/src/onboard/config.test.ts` around lines 146 - 156, Add a test in
the existing config.test.ts that verifies loadOnboardConfig() returns null when
the config file contains only whitespace; specifically, using the same
configPath pattern (`${homedir()}/.nemoclaw/config.json`) call
store.set(configPath, " \n\t ") (or similar whitespace string) and assert
expect(loadOnboardConfig()).toBeNull(); place this new it(...) alongside the
existing empty and malformed file tests so it covers the whitespace-only case.
Dockerfile (1)

32-66: Run the recommended sandbox E2E matrix for this image-layer change.

This change affects baked image layers and runtime tooling; please run the Dockerfile-targeted E2E jobs (cloud-e2e, sandbox-survival-e2e, hermes-e2e, rebuild-openclaw-e2e) before merge.

As per coding guidelines, Dockerfile changes are “only testable with a real container build” and include that E2E recommendation set.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Dockerfile` around lines 32 - 66, The Dockerfile change touches baked image
layers and runtime tooling (see the RUN blocks that modify apt packages and the
call to /usr/local/lib/nemoclaw/install-provider-tools.sh), so before merging
run the full Dockerfile-targeted E2E matrix: cloud-e2e, sandbox-survival-e2e,
hermes-e2e and rebuild-openclaw-e2e; build the image locally or in CI using this
Dockerfile, execute those test jobs against the resulting image, and only merge
once all tests pass to validate the apt cleanup/conditional installs and the
provider tools installer behavior.
agents/hermes/plugin/__init__.py (1)

671-708: Run Hermes E2E coverage for this tool-path change.

As per coding guidelines: agents/hermes/** changes should run hermes-e2e, hermes-inference-switch-e2e, hermes-discord-e2e, hermes-slack-e2e, rebuild-hermes-e2e, and rebuild-hermes-stale-base-e2e.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@agents/hermes/plugin/__init__.py` around lines 671 - 708, This change adds a
new tool registration (ctx.register_tool with name "openshell_network_access"
and handler _handle_network_access) under agents/hermes/plugin/__init__.py and
therefore requires running the Hermes E2E pipelines; please run or trigger
hermes-e2e, hermes-inference-switch-e2e, hermes-discord-e2e, hermes-slack-e2e,
rebuild-hermes-e2e, and rebuild-hermes-stale-base-e2e to validate the tool-path
change and include test results or fix any failing tests before merging.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@agents/hermes/plugin/__init__.py`:
- Around line 695-700: The schema entry "wait_timeout_ms" currently uses
DEFAULT_ACCESS_WAIT_MS (global default ~90000) which can cause action=check to
block; change the schema for "wait_timeout_ms" in
agents/hermes/plugin/__init__.py (the dict containing "wait_timeout_ms",
"minimum", "maximum", "default") to either remove the "default" key or set it to
0 so the action-multiplexed tool defaults to immediate (no wait) unless a caller
explicitly supplies a timeout; keep MAX_ACCESS_WAIT_MS and the min validation
intact.

In `@docs/reference/nemoclaw-openshell-integration.md`:
- Around line 1-2: Add the required YAML frontmatter block at the top of the new
Markdown file including at minimum title, description, and sidebar or permalink
fields, then immediately after that frontmatter add the SPDX Apache-2.0 license
header line (e.g. "SPDX-License-Identifier: Apache-2.0"); ensure the SPDX header
is present in the file and placed after the closing frontmatter delimiter (---)
per project guidelines so the page complies with docs frontmatter and license
requirements.

In `@nemoclaw/src/access-client.ts`:
- Around line 578-584: The target string is hardcoded to
"http://policy.local:80" and thus ignores a configured policyLocalUrl port;
update the target construction in the code that defines target so it derives
host and port from the configured policyLocalUrl (parse it with new
URL(policyLocalUrl) or use its origin) and fall back to proxy.port or default 80
only when policyLocalUrl has no explicit port; adjust the logic around target,
proxy.port and any use of base.pathname/requestPath so the final target uses the
correct hostname:port from policyLocalUrl rather than always :80.

In `@src/lib/onboard.ts`:
- Around line 1795-1805: The helper ensureProviderProfilesAvailable is adding
lines to onboard.ts and should be moved to a new module: create
src/lib/onboard/provider-profiles.ts exporting the function
ensureProviderProfilesAvailable which calls
providerProfileOnboard.ensureNemoClawProviderProfiles(runOpenshell, { log: note
}), handles the three result branches (unsupported, already-present with
skipped) using note, and calls policies.clearProviderProfileCache(); then
replace the body in src/lib/onboard.ts with a thin invocation that imports and
calls the exported ensureProviderProfilesAvailable to keep onboard.ts minimal
for the entrypoint budget gate.

---

Nitpick comments:
In `@agents/hermes/plugin/__init__.py`:
- Around line 671-708: This change adds a new tool registration
(ctx.register_tool with name "openshell_network_access" and handler
_handle_network_access) under agents/hermes/plugin/__init__.py and therefore
requires running the Hermes E2E pipelines; please run or trigger hermes-e2e,
hermes-inference-switch-e2e, hermes-discord-e2e, hermes-slack-e2e,
rebuild-hermes-e2e, and rebuild-hermes-stale-base-e2e to validate the tool-path
change and include test results or fix any failing tests before merging.

In `@Dockerfile`:
- Around line 32-66: The Dockerfile change touches baked image layers and
runtime tooling (see the RUN blocks that modify apt packages and the call to
/usr/local/lib/nemoclaw/install-provider-tools.sh), so before merging run the
full Dockerfile-targeted E2E matrix: cloud-e2e, sandbox-survival-e2e, hermes-e2e
and rebuild-openclaw-e2e; build the image locally or in CI using this
Dockerfile, execute those test jobs against the resulting image, and only merge
once all tests pass to validate the apt cleanup/conditional installs and the
provider tools installer behavior.

In `@docs/reference/nemoclaw-openshell-integration.md`:
- Around line 1-3: Add a one- or two-sentence introduction immediately after the
H1 "NemoClaw OpenShell Integration" and before the opening ```mermaid block; the
intro should briefly state the purpose of the page (what the integration covers
and who it’s for) so the document starts with the required summary sentence(s)
prior to the diagram.
- Line 76: The line containing "Each agent adapter exposes the same response
shape through the harness-native mechanism. OpenClaw uses its plugin API. Hermes
uses its Python plugin API. Additional harnesses can implement the same proposal
flow without changing the OpenShell policy API." must be split so each sentence
is on its own source line; edit that paragraph to place each of the four
sentences ("Each agent adapter exposes...", "OpenClaw uses its plugin API.",
"Hermes uses its Python plugin API.", "Additional harnesses can implement...")
on separate lines to satisfy the one-sentence-per-line docs rule.
- Around line 78-81: Add a terminal "Next Steps" section to the docs page that
provides links to related pages and closes the navigation block; specifically,
after the "## Provider Profiles" content add a new "## Next Steps" heading
followed by a short bullet or link list to related docs (e.g., onboarding,
policy presets, gateway integration) and ensure any required closing navigation
markup is present so the page meets the docs guideline for a terminal navigation
section.
- Line 80: Replace the single passive sentence starting "NemoClaw imports
OpenShell provider profiles..." with multiple active-voice sentences: keep the
first sentence as "NemoClaw imports OpenShell provider profiles for its policy
presets during onboarding," add a second active sentence like "NemoClaw leaves
existing OpenShell profiles unchanged," a third like "NemoClaw skips profiles it
already imported so onboarding is idempotent," and a final sentence for the
fallback: "If the OpenShell gateway does not support provider-profile import,
NemoClaw falls back to local presets." Ensure each sentence is on its own line
and update the exact sentence block in
docs/reference/nemoclaw-openshell-integration.md.

In `@nemoclaw/src/onboard/config.test.ts`:
- Around line 146-156: Add a test in the existing config.test.ts that verifies
loadOnboardConfig() returns null when the config file contains only whitespace;
specifically, using the same configPath pattern
(`${homedir()}/.nemoclaw/config.json`) call store.set(configPath, " \n\t ") (or
similar whitespace string) and assert expect(loadOnboardConfig()).toBeNull();
place this new it(...) alongside the existing empty and malformed file tests so
it covers the whitespace-only case.

In `@src/lib/onboard.ts`:
- Line 9751: This change adds ensureProviderProfilesAvailable() into the core
onboarding path in src/lib/onboard.ts; run the full onboarding E2E matrix to
validate it by executing the required jobs: cloud-e2e, sandbox-operations-e2e,
rebuild-openclaw-e2e, channels-stop-start-e2e,
messaging-compatible-endpoint-e2e, hermes-discord-e2e, hermes-slack-e2e, and
openshell-gateway-upgrade-e2e to ensure no regressions when
ensureProviderProfilesAvailable() runs during onboarding.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: a22b086d-b9e8-4c2b-8077-20979154aa94

📥 Commits

Reviewing files that changed from the base of the PR and between d7bae57 and 5516fbb.

📒 Files selected for processing (38)
  • Dockerfile
  • Dockerfile.base
  • agents/hermes/plugin/__init__.py
  • agents/hermes/plugin/plugin.yaml
  • docs/reference/nemoclaw-openshell-integration.md
  • nemoclaw-blueprint/policies/presets/github.yaml
  • nemoclaw-blueprint/provider-profiles/brave.yaml
  • nemoclaw-blueprint/provider-profiles/brew.yaml
  • nemoclaw-blueprint/provider-profiles/discord.yaml
  • nemoclaw-blueprint/provider-profiles/huggingface.yaml
  • nemoclaw-blueprint/provider-profiles/jira.yaml
  • nemoclaw-blueprint/provider-profiles/local-inference.yaml
  • nemoclaw-blueprint/provider-profiles/npm.yaml
  • nemoclaw-blueprint/provider-profiles/pypi.yaml
  • nemoclaw-blueprint/provider-profiles/slack.yaml
  • nemoclaw-blueprint/provider-profiles/telegram.yaml
  • nemoclaw/src/access-client.test.ts
  • nemoclaw/src/access-client.ts
  • nemoclaw/src/index.ts
  • nemoclaw/src/onboard/config.test.ts
  • nemoclaw/src/onboard/config.ts
  • nemoclaw/src/register.test.ts
  • scripts/generate-openclaw-config.py
  • scripts/install-provider-tools.sh
  • src/lib/onboard.ts
  • src/lib/onboard/provider-profiles.ts
  • src/lib/policy/index.ts
  • src/lib/sandbox/build-context.ts
  • test/e2e/hermes-policy-local-runner.py
  • test/e2e/nemoclaw-policy-local-runner.mjs
  • test/e2e/test-hermes-policy-local-plugin.sh
  • test/e2e/test-nemoclaw-policy-local-plugin.sh
  • test/generate-openclaw-config.test.ts
  • test/hermes-plugin-handlers.test.ts
  • test/policies.test.ts
  • test/provider-profile-onboard.test.ts
  • test/sandbox-build-context.test.ts
  • test/validate-blueprint.test.ts

Comment on lines +695 to +700
"wait_timeout_ms": {
"type": "number",
"minimum": 0,
"maximum": MAX_ACCESS_WAIT_MS,
"default": DEFAULT_ACCESS_WAIT_MS,
},

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Set wait_timeout_ms default to 0 (or remove schema default) for action-multiplexed tool.

Line 699 sets a global default of 90000, which can make action=check unexpectedly block if the caller applies schema defaults. check should default to immediate status unless explicitly asked to wait.

Suggested fix
                         "wait_timeout_ms": {
                             "type": "number",
                             "minimum": 0,
                             "maximum": MAX_ACCESS_WAIT_MS,
-                            "default": DEFAULT_ACCESS_WAIT_MS,
+                            "default": 0,
                         },
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"wait_timeout_ms": {
"type": "number",
"minimum": 0,
"maximum": MAX_ACCESS_WAIT_MS,
"default": DEFAULT_ACCESS_WAIT_MS,
},
"wait_timeout_ms": {
"type": "number",
"minimum": 0,
"maximum": MAX_ACCESS_WAIT_MS,
"default": 0,
},
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@agents/hermes/plugin/__init__.py` around lines 695 - 700, The schema entry
"wait_timeout_ms" currently uses DEFAULT_ACCESS_WAIT_MS (global default ~90000)
which can cause action=check to block; change the schema for "wait_timeout_ms"
in agents/hermes/plugin/__init__.py (the dict containing "wait_timeout_ms",
"minimum", "maximum", "default") to either remove the "default" key or set it to
0 so the action-multiplexed tool defaults to immediate (no wait) unless a caller
explicitly supplies a timeout; keep MAX_ACCESS_WAIT_MS and the min validation
intact.

Comment on lines +1 to +2
# NemoClaw OpenShell Integration

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add required frontmatter and SPDX header for a new docs page.

This new docs/** page is missing the required frontmatter block and SPDX license header placement.

As per coding guidelines, new docs pages must include frontmatter fields and an "SPDX license header is present after frontmatter," and every .md file must include an SPDX Apache-2.0 header.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/reference/nemoclaw-openshell-integration.md` around lines 1 - 2, Add the
required YAML frontmatter block at the top of the new Markdown file including at
minimum title, description, and sidebar or permalink fields, then immediately
after that frontmatter add the SPDX Apache-2.0 license header line (e.g.
"SPDX-License-Identifier: Apache-2.0"); ensure the SPDX header is present in the
file and placed after the closing frontmatter delimiter (---) per project
guidelines so the page complies with docs frontmatter and license requirements.

Comment on lines +578 to +584
const target = `http://policy.local:80${base.pathname.replace(/\/$/, "")}${requestPath}`;
const timeoutMs = options.timeoutMs ?? 310_000;
const proxyPort = proxy.port ? Number(proxy.port) : 80;
const headerLines = Object.entries(headers).map(([key, value]) => `${key}: ${value}`);
const requestBytes = [
`${method} ${target} HTTP/1.1`,
...headerLines,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Proxy target ignores configured policyLocalUrl port.

When proxying, the request target is hardcoded to policy.local:80, so a configured non-default policyLocalUrl port is silently dropped.

Suggested fix
-  const target = `http://policy.local:80${base.pathname.replace(/\/$/, "")}${requestPath}`;
+  const target = `${base.protocol}//${base.host}${base.pathname.replace(/\/$/, "")}${requestPath}`;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@nemoclaw/src/access-client.ts` around lines 578 - 584, The target string is
hardcoded to "http://policy.local:80" and thus ignores a configured
policyLocalUrl port; update the target construction in the code that defines
target so it derives host and port from the configured policyLocalUrl (parse it
with new URL(policyLocalUrl) or use its origin) and fall back to proxy.port or
default 80 only when policyLocalUrl has no explicit port; adjust the logic
around target, proxy.port and any use of base.pathname/requestPath so the final
target uses the correct hostname:port from policyLocalUrl rather than always
:80.

Comment thread src/lib/onboard.ts
Comment on lines +1795 to +1805
function ensureProviderProfilesAvailable(): void {
const result = providerProfileOnboard.ensureNemoClawProviderProfiles(runOpenshell, {
log: note,
});
if (result.status === "unsupported") {
note(` ${result.message}`);
} else if (result.status === "already-present" && result.skipped.length > 0) {
note(` NemoClaw provider profiles already registered: ${result.skipped.join(", ")}`);
}
policies.clearProviderProfileCache();
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Move this wrapper out of src/lib/onboard.ts to pass the entrypoint budget gate.

The onboard-entrypoint-budget CI check is currently failing (net +16 lines in this file), and this new helper is the main contributor. Extract the wrapper into src/lib/onboard/provider-profiles.ts and keep src/lib/onboard.ts to a thin invocation point.

Proposed direction
-const providerProfileOnboard: typeof import("./onboard/provider-profiles") =
-  require("./onboard/provider-profiles");
+const {
+  ensureProviderProfilesAvailable,
+}: typeof import("./onboard/provider-profiles") = require("./onboard/provider-profiles");

- function ensureProviderProfilesAvailable(): void {
-   const result = providerProfileOnboard.ensureNemoClawProviderProfiles(runOpenshell, {
-     log: note,
-   });
-   if (result.status === "unsupported") {
-     note(`  ${result.message}`);
-   } else if (result.status === "already-present" && result.skipped.length > 0) {
-     note(`  NemoClaw provider profiles already registered: ${result.skipped.join(", ")}`);
-   }
-   policies.clearProviderProfileCache();
- }
+// moved to ./onboard/provider-profiles

-    ensureProviderProfilesAvailable();
+    ensureProviderProfilesAvailable({
+      runOpenshell,
+      log: note,
+      clearProviderProfileCache: policies.clearProviderProfileCache,
+    });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/lib/onboard.ts` around lines 1795 - 1805, The helper
ensureProviderProfilesAvailable is adding lines to onboard.ts and should be
moved to a new module: create src/lib/onboard/provider-profiles.ts exporting the
function ensureProviderProfilesAvailable which calls
providerProfileOnboard.ensureNemoClawProviderProfiles(runOpenshell, { log: note
}), handles the three result branches (unsupported, already-present with
skipped) using note, and calls policies.clearProviderProfileCache(); then
replace the body in src/lib/onboard.ts with a thin invocation that imports and
calls the exported ensureProviderProfilesAvailable to keep onboard.ts minimal
for the entrypoint budget gate.

@cv cv left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Reviewed with the PR review advisor rubric (static patch review only; not evaluating CI/mergeability). Requesting changes:

  1. agents/hermes/plugin/__init__.py:367 uses quote(request_id) for proposal polling. Python's default safe='/' leaves slashes unescaped, so a user/tool-provided request id containing / changes the policy.local route. Please use quote(request_id, safe="") and add a regression test.
  2. agents/hermes/plugin/__init__.py:301 hardcodes proxy absolute-form requests to http://policy.local:80..., ignoring OPENSHELL_POLICY_LOCAL_URL host/port/path in proxy mode. Please derive the proxy target from _policy_local_base().
  3. agents/hermes/plugin/__init__.py:120 only normalizes GitHub hosts to canonical preset ids. Non-GitHub URLs such as PyPI/npm/Telegram become hostnames that list_presets does not return. Please either require exact preset ids or map all supported provider hosts to canonical ids.
  4. _all_presets() at agents/hermes/plugin/__init__.py:230-235 preserves fallback rules on provider-profile name collisions and only copies provider_profile. If provider profiles are available, their rule should replace the fallback rule (or this needs a clear source-of-truth rationale).
  5. This PR also inherits the TypeScript provider-profile/client blockers from the lower stack: non-unsupported OpenShell failures should not be downgraded to fallback, and provider endpoint ports need finite integer 1..65535 validation.

Please add Hermes tests for slash-containing request ids, custom policy.local proxy URLs, invalid provider-profile ports, and non-GitHub resource URLs.

@wscurran wscurran added area: policy Network policy, egress rules, presets, or sandbox policy area: sandbox OpenShell sandbox lifecycle, runtime, config, or recovery feature PR adds or expands user-visible functionality and removed OpenShell labels Jun 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: policy Network policy, egress rules, presets, or sandbox policy area: sandbox OpenShell sandbox lifecycle, runtime, config, or recovery feature PR adds or expands user-visible functionality integration: hermes Hermes integration behavior

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants