Skip to content

refactor(messaging): move build setup to manifest hooks#4949

Draft
sandl99 wants to merge 14 commits into
mainfrom
feat/issue-4395-manifest-hooks
Draft

refactor(messaging): move build setup to manifest hooks#4949
sandl99 wants to merge 14 commits into
mainfrom
feat/issue-4395-manifest-hooks

Conversation

@sandl99

@sandl99 sandl99 commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Summary

Migrate messaging build setup from legacy Docker build scripts and ad hoc build args into manifest-driven hooks. OpenClaw and Hermes now consume the staged messaging plan for package installs, static render outputs, and WeChat post-agent-install behavior.

Related Issue

Fixes #4395

Changes

  • Add common manifest hook support for static outputs and package-install build steps.
  • Replace the OpenClaw messaging build script with scripts/run-openclaw-build-hooks.mts and wire Docker builds through NEMOCLAW_MESSAGING_PLAN_B64.
  • Move Hermes messaging render/env handling to manifest hook application and remove agents/hermes/config/messaging-config.ts.
  • Remove old messaging build/env Docker args and deleted legacy script tests.
  • Update onboarding/rebuild/policy-channel tests and helpers for manifest plan based messaging setup.

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

Targeted checks run: npm run build:cli, npm run typecheck:cli, npx vitest run test/onboard-messaging.test.ts, npx vitest run src/lib/messaging/hooks/common/token-paste.test.ts, git diff --check.

  • 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
  • npm run 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: San Dang sdang@nvidia.com

Summary by CodeRabbit

  • Chores
    • Consolidated messaging configuration into a unified messaging plan build argument, replacing multiple separate messaging parameters.
    • Refactored messaging plugin installation and WeChat account seeding into a unified manifest-based build process, removing separate legacy scripts.
    • Streamlined Docker build flow for messaging setup across sandbox agents.

@sandl99 sandl99 self-assigned this Jun 8, 2026
@coderabbitai

coderabbitai Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: daef5a00-368d-41d6-8cbc-8c20ed7957d0

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
📝 Walkthrough

Walkthrough

This PR migrates NemoClaw's messaging configuration from legacy per-channel script-based logic to a unified base64-encoded manifest-driven plan system. It replaces multiple Docker build arguments with NEMOCLAW_MESSAGING_PLAN_B64, removes two Python scripts in favor of a TypeScript hook runner, refactors Hermes config generation to use manifest renders, and updates all messaging channel manifests to declare plugin installs and platform enablement through hooks and template-driven renders.

Changes

Messaging Plan System & Docker Build Integration

Layer / File(s) Summary
Messaging plan schema & Docker build args consolidation
Dockerfile, agents/hermes/Dockerfile, scripts/run-openclaw-build-hooks.mts, scripts/generate-openclaw-config.mts
Single ARG NEMOCLAW_MESSAGING_PLAN_B64 build arg replaces per-channel/platform legacy args. New TypeScript hook runner (run-openclaw-build-hooks.mts) reads and decodes the plan, installs OpenClaw plugins, and runs doctor. OpenClaw config generation parses the plan and applies agentRender JSON fragments and build-file steps.
Hermes config refactoring
agents/hermes/config/build-env.ts, agents/hermes/config/hermes-config.ts, agents/hermes/config/hermes-env.ts, agents/hermes/config/manifest-hooks.ts, agents/hermes/generate-config.ts
Remove explicit messaging types and env construction from build settings. Refactor buildHermesConfig to separate platform setup from toolset finalization. New buildHermesEnvLines handles API host/port and broker presets. New readHermesManifestHookPlan and applyHermesManifestHookRender read/apply the manifest plan for config/env updates.
Channel manifest plugin installs
src/lib/messaging/channels/discord/manifest.ts, src/lib/messaging/channels/slack/manifest.ts, src/lib/messaging/channels/telegram/manifest.ts, src/lib/messaging/channels/wechat/manifest.ts, src/lib/messaging/channels/whatsapp/manifest.ts
Discord, Slack, Telegram, WeChat, and WhatsApp manifests now declare agent-install hooks to install and pin OpenClaw/npm packages via common.staticOutputs. Add conditional JSON fragments (e.g., guilds when discord.hasGuilds is true) and Hermes platform enablement renders.
Manifest compiler & template rendering
src/lib/messaging/compiler/engines/agent-render-engine.ts, src/lib/messaging/compiler/engines/build-step-engine.ts, src/lib/messaging/compiler/engines/template.ts, src/lib/messaging/compiler/manifest-compiler.ts, src/lib/messaging/manifest/types.ts
Refactor planAgentRender and planBuildSteps to be async and hook-driven with template context. Replace credential templates with render templates supporting {{ ... }} references, proxy URL generation, and Discord/Slack/Telegram/WeChat/allowedIds templating. Add static-outputs hook registration. Extend manifest types with when conditions, agent-install/render phases, and hook metadata on plans.
Onboarding & Dockerfile patching
src/lib/onboard.ts, src/lib/onboard/dockerfile-patch.ts, src/lib/onboard/messaging-config.ts
Simplify sandbox creation by removing reusable messaging provider/channel derivation. Patch Dockerfile with serialized NEMOCLAW_MESSAGING_PLAN_B64 using MessagingSetupApplier.readPlanFromEnv() instead of individual messaging config args.
Sandbox rebuild & streaming support
src/lib/actions/sandbox/rebuild.ts, src/lib/adapters/openshell/client.ts, src/lib/adapters/openshell/runtime.ts
Add reapplyMessagingManifestAfterOpenClawDoctor() to reapply manifest hooks after doctor rebuild. Support optional stdin input?: string in openshell command options for passing data to executed commands.
Test infrastructure
test/messaging-plan-test-helper.ts
New helper exports withLegacyMessagingPlanEnv() to encode/normalize legacy env into NEMOCLAW_MESSAGING_PLAN_B64 for test compatibility. Supports legacy base64 channel/config decoding and Discord guild/mention-mode handling.
Test suite updates
test/generate-hermes-config.test.ts, test/generate-openclaw-config.test.ts, test/onboard-messaging.test.ts, test/onboard.test.ts, test/run-openclaw-build-hooks.test.ts, test/sandbox-build-context.test.ts, test/sandbox-provisioning.test.ts
Update tests to use withLegacyMessagingPlanEnv() for environment setup. Assert platform enablement and toolsets in Hermes config. Update OpenClaw WeChat tests to use canonical sandbox install path. Replace Python script tests with TypeScript hook runner tests.
Documentation & references
src/ext/wechat/qr.ts, src/lib/actions/sandbox/policy-channel.ts, agents/hermes/policy-additions.yaml, scripts/lib/sandbox-init.sh, test/e2e/test-messaging-providers.sh, test/e2e/docs/parity-inventory.generated.json
Update comments and documentation to reference wechat.seedOpenClawAccount manifest post-agent-install hook instead of scripts/seed-wechat-accounts.py. Update policy and test documentation to reflect manifest render/L7 proxy token resolution.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related issues

Possibly related PRs

  • NVIDIA/NemoClaw#4050: Introduces the manifest-style messaging architecture (ChannelManifests/ManifestCompiler/MessagingSetupApplier) that this PR consumes for base64-encoded plan application.
  • NVIDIA/NemoClaw#4536: Updates sandbox rebuild flow to reapply messaging manifest hooks instead of legacy WeChat seeding, directly aligning with rebuild changes in this PR.
  • NVIDIA/NemoClaw#4714: Both modify hermes-config.ts platform wiring; main PR refactors platform setup while retrieved PR adds Slack platform enabling.

Suggested labels

refactor, enhancement: messaging, area: messaging, v0.0.61

Suggested reviewers

  • ericksoa
  • cv

🐰 A plan so complete, it takes mere minutes,
From legacy scripts to manifests that spin it,
Discord and Slack now hooks do install,
WeChat seeds flow—no seed script at all! 🎯

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/issue-4395-manifest-hooks

Comment thread agents/hermes/config/manifest-hooks.ts Fixed
Comment thread scripts/generate-openclaw-config.mts Fixed
@github-actions

github-actions Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

E2E Advisor Recommendation

Required E2E: messaging-providers-e2e, channels-stop-start-e2e, hermes-discord-e2e, hermes-slack-e2e, rebuild-openclaw-e2e, rebuild-hermes-e2e, network-policy-e2e, hermes-secret-boundary-e2e
Optional E2E: channels-add-remove-e2e, cloud-onboard-e2e, hermes-root-entrypoint-smoke-e2e, inference-routing-e2e

Dispatch hint: messaging-providers-e2e,channels-stop-start-e2e,hermes-discord-e2e,hermes-slack-e2e,rebuild-openclaw-e2e,rebuild-hermes-e2e,network-policy-e2e,hermes-secret-boundary-e2e

Workflow run

Full advisor summary

E2E Recommendation Advisor

Base: origin/main
Head: HEAD
Confidence: high

Required E2E

  • messaging-providers-e2e (high): Highest-signal existing coverage for this PR: validates OpenClaw messaging provider creation, placeholder/config baking, no-secret leakage, network reachability, L7 token rewriting, Discord gateway path, WeChat seeded account metadata, and WhatsApp QR-only parity. The PR rewrites exactly those build/config paths.
  • channels-stop-start-e2e (high): Required because channel stop/start/rebuild behavior depends on the new messaging build plan and manifest hook outputs. This existing job explicitly exercises OpenClaw and Hermes across telegram, discord, wechat, slack, and whatsapp channel lifecycle.
  • hermes-discord-e2e (medium): Hermes Discord config moved from Hermes-specific code into shared messaging manifests/applier phases. This validates Hermes Discord onboarding, schema/rendering, provider placeholders, and OpenShell credential rewrite path.
  • hermes-slack-e2e (medium): Hermes Slack token/app-token handling, policy, and placeholder rewrite path are affected by the shared messaging plan conversion and Hermes Dockerfile/config changes.
  • rebuild-openclaw-e2e (medium): OpenClaw Dockerfile, config generation, messaging applier phases, sandbox build context, and rebuild code changed. This verifies rebuild preserves state/policy and still supports post-rebuild inference after the new image build flow.
  • rebuild-hermes-e2e (medium): Hermes Dockerfile/config generation now copies and runs shared messaging applier code in multiple phases. This validates Hermes rebuild behavior and state preservation after those image-build changes.
  • network-policy-e2e (medium): Hermes policy additions and sandbox policy-channel logic changed near messaging egress and credential-rewrite boundaries. Network policy E2E should block merge because policy regressions can leak or over-permit external traffic.
  • hermes-secret-boundary-e2e (medium): Hermes image now includes shared messaging source and build applier outputs; messaging placeholders and managed env generation changed. This verifies raw secret-shaped values do not enter Hermes sandbox env/config.

Optional E2E

  • channels-add-remove-e2e (high): Useful adjacent confidence for channel add/remove lifecycle and credential reuse on rebuild after the messaging build-plan refactor, but channels-stop-start plus messaging-providers cover the most merge-blocking paths.
  • cloud-onboard-e2e (medium): Broad source-install/onboard smoke with custom policy inputs; useful because src/lib/onboard.ts and Dockerfile patching changed, though messaging-specific required tests provide more targeted coverage.
  • hermes-root-entrypoint-smoke-e2e (medium): Hermes Dockerfile changed file copy paths, permissions, and build-time applier execution. The secret-boundary and rebuild tests are stronger, but this is a useful faster image/entrypoint smoke.
  • inference-routing-e2e (medium): OpenShell runtime/client and base config generation changed near provider routing; optional because the PR is primarily messaging/build-plan oriented and rebuild tests include post-rebuild inference.

New E2E recommendations

  • hermes-messaging-provider-parity (high): Existing dedicated Hermes messaging E2Es cover Discord and Slack, while this PR moves all Hermes channels to the shared manifest/applier model. Add a Hermes-focused E2E for Telegram plus WeChat/WhatsApp render/start parity to catch agent-specific manifest hook regressions not covered by OpenClaw-centric provider tests.
    • Suggested test: Add a Hermes messaging parity E2E that onboards Hermes with telegram, wechat, and whatsapp using fake/synthetic credentials or QR metadata, asserts .hermes/config.yaml and .env render outputs, verifies provider/placeholder no-secret boundaries, and checks channel lifecycle after rebuild.
  • messaging-build-plan-phase-contract (medium): The old Python build scripts were replaced by TypeScript manifest build phases. Unit tests cover planning, but an image-level E2E would catch Docker path, permission, phase-order, and node --experimental-strip-types issues across OpenClaw and Hermes.
    • Suggested test: Add a fast image-build E2E that builds OpenClaw and Hermes images with a synthetic NEMOCLAW_MESSAGING_PLAN_B64 containing multiple channels, then inspects generated config files, plugin installs, hook output files, and permissions without requiring live provider APIs.

Dispatch hint

  • Workflow: .github/workflows/nightly-e2e.yaml
  • jobs input: messaging-providers-e2e,channels-stop-start-e2e,hermes-discord-e2e,hermes-slack-e2e,rebuild-openclaw-e2e,rebuild-hermes-e2e,network-policy-e2e,hermes-secret-boundary-e2e

@github-actions

github-actions Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

E2E Scenario Advisor Recommendation

Required scenario E2E: ubuntu-repo-cloud-openclaw, ubuntu-repo-cloud-hermes, ubuntu-repo-cloud-openclaw-telegram, ubuntu-repo-cloud-openclaw-discord, ubuntu-repo-cloud-openclaw-slack, ubuntu-repo-cloud-hermes-discord, ubuntu-repo-cloud-hermes-slack, ubuntu-repo-cloud-openclaw-custom-policies, ubuntu-repo-cloud-openclaw-token-rotation, ubuntu-rebuild-openclaw
Optional scenario E2E: wsl-repo-cloud-openclaw, macos-repo-cloud-openclaw, gpu-repo-local-ollama-openclaw

Dispatch required scenario E2E:

  • gh workflow run e2e-scenarios.yaml --ref <pr-head-ref> --field scenarios=ubuntu-repo-cloud-openclaw
  • gh workflow run e2e-scenarios.yaml --ref <pr-head-ref> --field scenarios=ubuntu-repo-cloud-hermes
  • gh workflow run e2e-scenarios.yaml --ref <pr-head-ref> --field scenarios=ubuntu-repo-cloud-openclaw-telegram
  • gh workflow run e2e-scenarios.yaml --ref <pr-head-ref> --field scenarios=ubuntu-repo-cloud-openclaw-discord
  • gh workflow run e2e-scenarios.yaml --ref <pr-head-ref> --field scenarios=ubuntu-repo-cloud-openclaw-slack
  • gh workflow run e2e-scenarios.yaml --ref <pr-head-ref> --field scenarios=ubuntu-repo-cloud-hermes-discord
  • gh workflow run e2e-scenarios.yaml --ref <pr-head-ref> --field scenarios=ubuntu-repo-cloud-hermes-slack
  • gh workflow run e2e-scenarios.yaml --ref <pr-head-ref> --field scenarios=ubuntu-repo-cloud-openclaw-custom-policies
  • gh workflow run e2e-scenarios.yaml --ref <pr-head-ref> --field scenarios=ubuntu-repo-cloud-openclaw-token-rotation
  • gh workflow run e2e-scenarios.yaml --ref <pr-head-ref> --field scenarios=ubuntu-rebuild-openclaw

Workflow run

Full scenario advisor summary

E2E Scenario Advisor

Base: origin/main
Head: HEAD
Confidence: high

Required scenario E2E

  • ubuntu-repo-cloud-openclaw: Covers the primary OpenClaw repo-install/cloud onboarding path after Dockerfile, openclaw config generation, sandbox init, build-context, OpenShell adapter, and onboarding changes.
    • Dispatch: gh workflow run e2e-scenarios.yaml --ref <pr-head-ref> --field scenarios=ubuntu-repo-cloud-openclaw
  • ubuntu-repo-cloud-hermes: Covers the primary Hermes repo-install/cloud onboarding path after Hermes Dockerfile/config generation changes and shared messaging applier integration into Hermes images.
    • Dispatch: gh workflow run e2e-scenarios.yaml --ref <pr-head-ref> --field scenarios=ubuntu-repo-cloud-hermes
  • ubuntu-repo-cloud-openclaw-telegram: Telegram manifest/template resolver and shared messaging plan compiler/applier changed; this is the routed OpenClaw scenario exercising the Telegram messaging suite.
    • Dispatch: gh workflow run e2e-scenarios.yaml --ref <pr-head-ref> --field scenarios=ubuntu-repo-cloud-openclaw-telegram
  • ubuntu-repo-cloud-openclaw-discord: Discord manifest/template resolver and shared messaging plan compiler/applier changed; this is the routed OpenClaw scenario exercising the Discord messaging suite.
    • Dispatch: gh workflow run e2e-scenarios.yaml --ref <pr-head-ref> --field scenarios=ubuntu-repo-cloud-openclaw-discord
  • ubuntu-repo-cloud-openclaw-slack: Slack manifest/template resolver and shared messaging plan compiler/applier changed; this is the routed OpenClaw scenario exercising the Slack messaging suite.
    • Dispatch: gh workflow run e2e-scenarios.yaml --ref <pr-head-ref> --field scenarios=ubuntu-repo-cloud-openclaw-slack
  • ubuntu-repo-cloud-hermes-discord: Hermes messaging config moved from agent-specific generation to shared manifest render hooks; this exercises Discord messaging on the Hermes agent path.
    • Dispatch: gh workflow run e2e-scenarios.yaml --ref <pr-head-ref> --field scenarios=ubuntu-repo-cloud-hermes-discord
  • ubuntu-repo-cloud-hermes-slack: Hermes messaging config moved from agent-specific generation to shared manifest render hooks; this exercises Slack messaging on the Hermes agent path.
    • Dispatch: gh workflow run e2e-scenarios.yaml --ref <pr-head-ref> --field scenarios=ubuntu-repo-cloud-hermes-slack
  • ubuntu-repo-cloud-openclaw-custom-policies: Policy-channel and policy-addition surfaces changed; this scenario exercises custom policy onboarding state on the OpenClaw path.
    • Dispatch: gh workflow run e2e-scenarios.yaml --ref <pr-head-ref> --field scenarios=ubuntu-repo-cloud-openclaw-custom-policies
  • ubuntu-repo-cloud-openclaw-token-rotation: Messaging credential placeholder/rendering and OpenShell credential-boundary code changed; token rotation is the targeted scenario for provider credential isolation in messaging.
    • Dispatch: gh workflow run e2e-scenarios.yaml --ref <pr-head-ref> --field scenarios=ubuntu-repo-cloud-openclaw-token-rotation
  • ubuntu-rebuild-openclaw: Rebuild action, Dockerfile patching/build args, build context, and messaging build applier integration changed; run the routed rebuild scenario to verify image rebuild behavior.
    • Dispatch: gh workflow run e2e-scenarios.yaml --ref <pr-head-ref> --field scenarios=ubuntu-rebuild-openclaw

Optional scenario E2E

  • wsl-repo-cloud-openclaw: Optional platform adjacency for sandbox init/OpenShell runtime/onboarding changes; WSL uses a special Windows runner, so keep it optional unless platform-specific regressions are suspected.
    • Dispatch: gh workflow run e2e-scenarios.yaml --ref <pr-head-ref> --field scenarios=wsl-repo-cloud-openclaw
  • macos-repo-cloud-openclaw: Optional platform adjacency for onboarding and Dockerfile patch behavior on macOS; special-runner/platform scenario and not the primary changed surface.
    • Dispatch: gh workflow run e2e-scenarios.yaml --ref <pr-head-ref> --field scenarios=macos-repo-cloud-openclaw
  • gpu-repo-local-ollama-openclaw: Optional adjacent provider/runtime coverage for OpenClaw config and Dockerfile changes on the local Ollama GPU path; special GPU runner, so not required by default.
    • Dispatch: gh workflow run e2e-scenarios.yaml --ref <pr-head-ref> --field scenarios=gpu-repo-local-ollama-openclaw

Relevant changed files

  • Dockerfile
  • agents/hermes/Dockerfile
  • agents/hermes/config/build-env.ts
  • agents/hermes/config/hermes-config.ts
  • agents/hermes/config/hermes-env.ts
  • agents/hermes/config/messaging-config.ts
  • agents/hermes/generate-config.ts
  • agents/hermes/policy-additions.yaml
  • scripts/generate-openclaw-config.mts
  • scripts/lib/sandbox-init.sh
  • scripts/openclaw-build-messaging-plugins.py
  • scripts/seed-wechat-accounts.py
  • src/ext/wechat/qr.ts
  • src/lib/actions/sandbox/policy-channel.ts
  • src/lib/actions/sandbox/rebuild.ts
  • src/lib/adapters/openshell/client.ts
  • src/lib/adapters/openshell/runtime.ts
  • src/lib/messaging/applier/agent-config.ts
  • src/lib/messaging/applier/build/messaging-build-applier.mts
  • src/lib/messaging/channels/discord/manifest.ts
  • src/lib/messaging/channels/discord/template-resolver.ts
  • src/lib/messaging/channels/index.ts
  • src/lib/messaging/channels/slack/manifest.ts
  • src/lib/messaging/channels/slack/template-resolver.ts
  • src/lib/messaging/channels/telegram/manifest.ts
  • src/lib/messaging/channels/telegram/template-resolver.ts
  • src/lib/messaging/channels/template-resolver-utils.ts
  • src/lib/messaging/channels/template-resolver.ts
  • src/lib/messaging/channels/wechat/hooks/seed-openclaw-account.ts
  • src/lib/messaging/channels/wechat/manifest.ts
  • src/lib/messaging/channels/wechat/template-resolver.ts
  • src/lib/messaging/channels/whatsapp/manifest.ts
  • src/lib/messaging/channels/whatsapp/template-resolver.ts
  • src/lib/messaging/compiler/engines/agent-render-engine.ts
  • src/lib/messaging/compiler/engines/build-step-engine.ts
  • src/lib/messaging/compiler/engines/template.ts
  • src/lib/messaging/compiler/manifest-compiler.ts
  • src/lib/messaging/compiler/workflow-planner.ts
  • src/lib/messaging/hooks/common/index.ts
  • src/lib/messaging/hooks/common/static-outputs.ts
  • src/lib/messaging/hooks/common/token-paste.test.ts
  • src/lib/messaging/hooks/hook-runner.test.ts
  • src/lib/messaging/manifest/types.ts
  • src/lib/onboard.ts
  • src/lib/onboard/dockerfile-patch.ts
  • src/lib/onboard/messaging-channel-setup.ts
  • src/lib/onboard/messaging-config.ts
  • src/lib/onboard/wechat-config.ts
  • src/lib/sandbox/build-context.ts

@github-actions

github-actions Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

PR Review Advisor

Findings: 2 needs attention, 5 worth checking, 1 nice ideas
Since last review: 0 prior items resolved, 1 still applies, 5 new items found

Review findings

🛠️ Needs attention

  • OpenClaw doctor can undo freshly rendered messaging config during image build (src/lib/messaging/applier/build/messaging-build-applier.mts:938): The post-agent-install build phase applies manifest render/build-file outputs and then runs `openclaw doctor --fix --non-interactive`. The rebuild path explicitly documents that doctor may rewrite `openclaw.json` after messaging render and therefore reapplies the plan after doctor, but the Docker image build path does not reapply. That leaves an acceptance risk that channels or WeChat account seed patches are present when doctor starts but missing in the final image layer before sandbox startup.
    • Recommendation: Run OpenClaw doctor before applying manifest render/build-file outputs, or reapply the manifest plan after doctor in the image build path. Add a regression test where a mocked doctor rewrites `openclaw.json` and the final file still contains `channels.discord`, plugin entries, and WeChat account patches.
    • Evidence: `applyMessagingBuildPhase` combines `applyMessagingAgentRenderToLocalFiles`, `applyPostAgentInstallBuildFilesToLocalFiles`, then `runOpenClawMessagingDoctor`; `src/lib/actions/sandbox/rebuild.ts` comments at the post-doctor reapply path say doctor may rewrite `openclaw.json` after image-build messaging outputs.
  • Large-file hotspots grew during the refactor: This PR expands several existing monolith hotspots while adding a broad messaging build-applier refactor. The deterministic size budget flags blocker-sized growth in `src/lib/messaging/compiler/manifest-compiler.ts` (+47), `src/lib/messaging/compiler/manifest-compiler.test.ts` (+56), `src/lib/actions/sandbox/rebuild.ts` (+42), and `src/lib/messaging/compiler/workflow-planner.test.ts` (+26).
    • Recommendation: Extract new planner/compiler/rebuild helper logic or offset the growth in the same hotspots before merge. If a size budget must change, keep it tied to a concrete extraction plan rather than normalizing growth in already-large files.
    • Evidence: Monolith delta context marks those four files as blocker because current large-file hotspots grew by 20 or more lines.

🔎 Worth checking

  • Source-of-truth review needed: OpenClaw image build post-agent-install messaging apply plus doctor: The advisor marked localized patch analysis as missing.
    • Recommendation: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
    • Evidence: `messaging-build-applier.mts` runs `runOpenClawMessagingDoctor` after local render/build-file application, while rebuild comments state doctor may rewrite `openclaw.json` after image-build messaging outputs.
  • Source-of-truth review needed: Rebuild post-doctor messaging manifest reapply: The advisor marked localized patch analysis as needs_followup.
    • Recommendation: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
    • Evidence: `src/lib/actions/sandbox/rebuild.ts` catches and logs post-doctor reapply errors instead of making the rebuild outcome reflect that messaging restoration failed.
  • Rendered Hermes env values strip CR but not LF (src/lib/messaging/channels/template-resolver-utils.ts:52): Messaging env-line rendering can place externally sourced WeChat metadata into Hermes `.env` entries such as `WEIXIN_BASE_URL={{wechatConfig.baseUrl}}`. The shared `cleanString` helper strips carriage returns but preserves line feeds, and the WeChat host-QR hook stores `baseUrl`, `accountId`, and `userId` returned by the host-QR flow into env/config values. A malicious or malformed value containing `\n` could inject additional `.env` lines into the generated Hermes config.
    • Recommendation: Reject or escape both `\r` and `\n` for all values rendered into env-line outputs, and validate WeChat `baseUrl` with an HTTPS + expected iLink host allowlist before persisting/rendering it. Add a negative test proving LF-containing WeChat metadata cannot add a second `.env` key.
    • Evidence: `cleanString` uses `String(value ?? "").replace(/\r/g, "").trim()`; `wechat/manifest.ts` renders `WEIXIN_BASE_URL={{wechatConfig.baseUrl}}`; `ilink-login.ts` assigns `env.WECHAT_BASE_URL = baseUrl` when the host-QR result supplies it.
  • Rebuild silently downgrades messaging reapply failures (src/lib/actions/sandbox/rebuild.ts:257): The post-doctor rebuild recovery catches all errors from `MessagingSetupApplier.applyAgentConfigAtOpenShell` and prints a dim 'skipped' message. Because the code comments say this reapply is needed after `openclaw doctor --fix` may rewrite channel config, a failure can leave a rebuilt sandbox with broken messaging or WeChat state without a clear degraded rebuild result.
    • Recommendation: Surface this as a prominent warning or fail/degrade the rebuild result when enabled messaging channels need reapply. Add a test where the reapply command fails after doctor and the user-visible rebuild result clearly reports messaging config was not restored.
    • Evidence: `reapplyMessagingManifestAfterOpenClawDoctor` catches `err`, logs `Messaging manifest reapply failed`, and prints `Messaging manifest config reapply skipped (...)` instead of propagating or marking rebuild degraded.
  • Runtime validation is still needed for Docker/Hermes build-time messaging hooks (Dockerfile:451): The tests exercise generator and applier behavior with mocks, but this PR changes Dockerfile build ordering, image contents, copied trusted TypeScript, Hermes config generation, plugin installation, and WeChat seed files. These sandbox/runtime paths need targeted validation beyond unit-level snapshots.
    • Recommendation: Add or identify behavior-specific runtime validation that builds or inspects an OpenClaw and Hermes sandbox image with representative channels and verifies generated files/configs exist before startup, without relying on external job status in the review surface.
    • Evidence: Changed runtime surfaces include both Dockerfiles, `scripts/generate-openclaw-config.mts`, Hermes config generation, `messaging-build-applier.mts`, and sandbox rebuild glue; trusted test-depth context reports `runtime_validation_recommended` for these files.

🌱 Nice ideas

  • Avoid `@ts-nocheck` in new security-sensitive build-applier tests (test/messaging-build-applier.test.ts:1): The new build-applier test file disables TypeScript checking while exercising serialized plan shapes, build-file outputs, and path/mode security boundaries. That weakens caller/callee contract verification around exactly the data structures this refactor depends on.
    • Recommendation: Remove `// @ts-nocheck` from the new test or narrow it to specific fixtures with typed helpers so malformed plan shapes are caught by the compiler where possible.
    • Evidence: `test/messaging-build-applier.test.ts` starts with `// @ts-nocheck`.
Consider writing more tests for
  • **Runtime validation** — OpenClaw post-agent-install applier preserves messaging config when `openclaw doctor --fix` rewrites `openclaw.json`.. This PR changes Dockerfile image-build sequencing, copied trusted TypeScript, Hermes config generation, OpenClaw plugin installation, WeChat build-file seeding, and sandbox rebuild recovery. Unit and snapshot coverage is helpful, but runtime/sandbox behavior still needs targeted validation.
  • **Runtime validation** — Dockerfile build sequence leaves `channels.discord`, `plugins.entries.slack`, and `channels.openclaw-weixin.accounts` present after the post-agent-install doctor step.. This PR changes Dockerfile image-build sequencing, copied trusted TypeScript, Hermes config generation, OpenClaw plugin installation, WeChat build-file seeding, and sandbox rebuild recovery. Unit and snapshot coverage is helpful, but runtime/sandbox behavior still needs targeted validation.
  • **Runtime validation** — Hermes env render rejects or safely quotes WeChat `baseUrl`, `accountId`, `userId`, and allowed IDs containing LF.. This PR changes Dockerfile image-build sequencing, copied trusted TypeScript, Hermes config generation, OpenClaw plugin installation, WeChat build-file seeding, and sandbox rebuild recovery. Unit and snapshot coverage is helpful, but runtime/sandbox behavior still needs targeted validation.
  • **Runtime validation** — Rebuild reports a prominent warning or degraded result when post-doctor messaging manifest reapply fails.. This PR changes Dockerfile image-build sequencing, copied trusted TypeScript, Hermes config generation, OpenClaw plugin installation, WeChat build-file seeding, and sandbox rebuild recovery. Unit and snapshot coverage is helpful, but runtime/sandbox behavior still needs targeted validation.
  • **Runtime validation** — Serialized messaging plans generated from token-paste and host-QR inputs do not contain raw `TELEGRAM_BOT_TOKEN`, `SLACK_BOT_TOKEN`, `SLACK_APP_TOKEN`, or `WECHAT_BOT_TOKEN` values.. This PR changes Dockerfile image-build sequencing, copied trusted TypeScript, Hermes config generation, OpenClaw plugin installation, WeChat build-file seeding, and sandbox rebuild recovery. Unit and snapshot coverage is helpful, but runtime/sandbox behavior still needs targeted validation.
  • **Runtime validation is still needed for Docker/Hermes build-time messaging hooks** — Add or identify behavior-specific runtime validation that builds or inspects an OpenClaw and Hermes sandbox image with representative channels and verifies generated files/configs exist before startup, without relying on external job status in the review surface.
  • **Avoid `@ts-nocheck` in new security-sensitive build-applier tests** — Remove `// @ts-nocheck` from the new test or narrow it to specific fixtures with typed helpers so malformed plan shapes are caught by the compiler where possible.
  • **Acceptance clause:** OpenClaw `openclaw.json` snapshots match current Telegram, Discord, Slack, WeChat, and WhatsApp behavior. — add test evidence or identify existing coverage. Snapshot/applier tests cover Telegram, Discord, Slack, WeChat, and WhatsApp behavior in `test/generate-openclaw-config.test.ts` and `test/messaging-build-applier.test.ts`; however the post-agent-install doctor ordering can change the final OpenClaw config after those render outputs are written.
Since last review details

Current findings:

  • Source-of-truth review needed: OpenClaw image build post-agent-install messaging apply plus doctor: The advisor marked localized patch analysis as missing.
    • Recommendation: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
    • Evidence: `messaging-build-applier.mts` runs `runOpenClawMessagingDoctor` after local render/build-file application, while rebuild comments state doctor may rewrite `openclaw.json` after image-build messaging outputs.
  • Source-of-truth review needed: Rebuild post-doctor messaging manifest reapply: The advisor marked localized patch analysis as needs_followup.
    • Recommendation: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
    • Evidence: `src/lib/actions/sandbox/rebuild.ts` catches and logs post-doctor reapply errors instead of making the rebuild outcome reflect that messaging restoration failed.
  • OpenClaw doctor can undo freshly rendered messaging config during image build (src/lib/messaging/applier/build/messaging-build-applier.mts:938): The post-agent-install build phase applies manifest render/build-file outputs and then runs `openclaw doctor --fix --non-interactive`. The rebuild path explicitly documents that doctor may rewrite `openclaw.json` after messaging render and therefore reapplies the plan after doctor, but the Docker image build path does not reapply. That leaves an acceptance risk that channels or WeChat account seed patches are present when doctor starts but missing in the final image layer before sandbox startup.
    • Recommendation: Run OpenClaw doctor before applying manifest render/build-file outputs, or reapply the manifest plan after doctor in the image build path. Add a regression test where a mocked doctor rewrites `openclaw.json` and the final file still contains `channels.discord`, plugin entries, and WeChat account patches.
    • Evidence: `applyMessagingBuildPhase` combines `applyMessagingAgentRenderToLocalFiles`, `applyPostAgentInstallBuildFilesToLocalFiles`, then `runOpenClawMessagingDoctor`; `src/lib/actions/sandbox/rebuild.ts` comments at the post-doctor reapply path say doctor may rewrite `openclaw.json` after image-build messaging outputs.
  • Rendered Hermes env values strip CR but not LF (src/lib/messaging/channels/template-resolver-utils.ts:52): Messaging env-line rendering can place externally sourced WeChat metadata into Hermes `.env` entries such as `WEIXIN_BASE_URL={{wechatConfig.baseUrl}}`. The shared `cleanString` helper strips carriage returns but preserves line feeds, and the WeChat host-QR hook stores `baseUrl`, `accountId`, and `userId` returned by the host-QR flow into env/config values. A malicious or malformed value containing `\n` could inject additional `.env` lines into the generated Hermes config.
    • Recommendation: Reject or escape both `\r` and `\n` for all values rendered into env-line outputs, and validate WeChat `baseUrl` with an HTTPS + expected iLink host allowlist before persisting/rendering it. Add a negative test proving LF-containing WeChat metadata cannot add a second `.env` key.
    • Evidence: `cleanString` uses `String(value ?? "").replace(/\r/g, "").trim()`; `wechat/manifest.ts` renders `WEIXIN_BASE_URL={{wechatConfig.baseUrl}}`; `ilink-login.ts` assigns `env.WECHAT_BASE_URL = baseUrl` when the host-QR result supplies it.
  • Rebuild silently downgrades messaging reapply failures (src/lib/actions/sandbox/rebuild.ts:257): The post-doctor rebuild recovery catches all errors from `MessagingSetupApplier.applyAgentConfigAtOpenShell` and prints a dim 'skipped' message. Because the code comments say this reapply is needed after `openclaw doctor --fix` may rewrite channel config, a failure can leave a rebuilt sandbox with broken messaging or WeChat state without a clear degraded rebuild result.
    • Recommendation: Surface this as a prominent warning or fail/degrade the rebuild result when enabled messaging channels need reapply. Add a test where the reapply command fails after doctor and the user-visible rebuild result clearly reports messaging config was not restored.
    • Evidence: `reapplyMessagingManifestAfterOpenClawDoctor` catches `err`, logs `Messaging manifest reapply failed`, and prints `Messaging manifest config reapply skipped (...)` instead of propagating or marking rebuild degraded.
  • Large-file hotspots grew during the refactor: This PR expands several existing monolith hotspots while adding a broad messaging build-applier refactor. The deterministic size budget flags blocker-sized growth in `src/lib/messaging/compiler/manifest-compiler.ts` (+47), `src/lib/messaging/compiler/manifest-compiler.test.ts` (+56), `src/lib/actions/sandbox/rebuild.ts` (+42), and `src/lib/messaging/compiler/workflow-planner.test.ts` (+26).
    • Recommendation: Extract new planner/compiler/rebuild helper logic or offset the growth in the same hotspots before merge. If a size budget must change, keep it tied to a concrete extraction plan rather than normalizing growth in already-large files.
    • Evidence: Monolith delta context marks those four files as blocker because current large-file hotspots grew by 20 or more lines.
  • Runtime validation is still needed for Docker/Hermes build-time messaging hooks (Dockerfile:451): The tests exercise generator and applier behavior with mocks, but this PR changes Dockerfile build ordering, image contents, copied trusted TypeScript, Hermes config generation, plugin installation, and WeChat seed files. These sandbox/runtime paths need targeted validation beyond unit-level snapshots.
    • Recommendation: Add or identify behavior-specific runtime validation that builds or inspects an OpenClaw and Hermes sandbox image with representative channels and verifies generated files/configs exist before startup, without relying on external job status in the review surface.
    • Evidence: Changed runtime surfaces include both Dockerfiles, `scripts/generate-openclaw-config.mts`, Hermes config generation, `messaging-build-applier.mts`, and sandbox rebuild glue; trusted test-depth context reports `runtime_validation_recommended` for these files.
  • Avoid `@ts-nocheck` in new security-sensitive build-applier tests (test/messaging-build-applier.test.ts:1): The new build-applier test file disables TypeScript checking while exercising serialized plan shapes, build-file outputs, and path/mode security boundaries. That weakens caller/callee contract verification around exactly the data structures this refactor depends on.
    • Recommendation: Remove `// @ts-nocheck` from the new test or narrow it to specific fixtures with typed helpers so malformed plan shapes are caught by the compiler where possible.
    • Evidence: `test/messaging-build-applier.test.ts` starts with `// @ts-nocheck`.

Workflow run details

This is an automated advisory review. A human maintainer must make the final merge decision.

@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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
src/lib/onboard.ts (1)

3383-3387: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Preserve Telegram mention policy across channels stop/start.

Line 3383 now gates telegramConfig on activeMessagingChannels, which excludes temporarily disabled channels. A rebuild after channels stop telegram will therefore persist current.telegramConfig = null, so a later channels start telegram loses the prior TELEGRAM_REQUIRE_MENTION behavior unless the operator re-exports it. This should key off the configured channel set (enabledChannels / persisted messaging channels), not only the currently attached providers.

Suggested fix
-  if (activeMessagingChannels.includes("telegram")) {
+  const telegramConfigured =
+    enabledChannels?.includes("telegram") ?? activeMessagingChannels.includes("telegram");
+  if (telegramConfigured) {
     const telegramRequireMention = computeTelegramRequireMention();
     if (telegramRequireMention !== null) {
       telegramConfig.requireMention = telegramRequireMention;
     }
   }

Based on learnings, channel state is expected to persist durably across rebuilds, and the PR objective explicitly calls out rebuild-hydration parity for Telegram config.

🤖 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 3383 - 3387, The current guard uses
activeMessagingChannels to decide whether to set telegramConfig.requireMention,
which drops the persisted Telegram mention policy when providers are temporarily
stopped; change the check to use the persisted/configured channel set (e.g.,
enabledChannels or enabledMessagingChannels / persisted messaging channels)
instead of activeMessagingChannels so computeTelegramRequireMention() runs
whenever Telegram is configured, not only when a provider is attached; update
the block around telegramConfig and computeTelegramRequireMention to key off
that persisted/enable set (ensure you reference telegramConfig,
computeTelegramRequireMention, and the enabledChannels/enabledMessagingChannels
variable) so TELEGRAM_REQUIRE_MENTION survives channels stop/start cycles.

Source: Learnings

test/generate-openclaw-config.test.ts (1)

1-4: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Update the stale legacy test-size budget entry to unblock CI.

The pipeline is failing because this file is now 2105 lines while the recorded legacy budget remains 2106. Please lower the corresponding budget entry to match the current line count so codebase-growth-guardrails passes.

🤖 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 `@test/generate-openclaw-config.test.ts` around lines 1 - 4, The recorded
legacy "test-size" budget entry is off by one (recorded 2106 vs actual 2105
lines) causing CI failures; update the legacy test-size budget value to 2105 to
match test/generate-openclaw-config.test.ts current line count so
codebase-growth-guardrails passes—locate the budget entry named "legacy
test-size" (or the test-size entry used by the codebase-growth-guardrails
config) and lower its numeric value from 2106 to 2105.

Source: Pipeline failures

src/lib/messaging/compiler/manifest-compiler.ts (1)

333-343: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

validValues is bypassed for config env values.

At Line 337, config-resolved values return before the validValues gate at Line 342. That lets out-of-range config values pass manifest constraints.

Suggested fix
 function readInputEnvValue(input: ChannelInputSpec): MessagingSerializableValue | undefined {
+  const normalize = (raw: string | undefined): string | undefined => {
+    const normalized = raw?.replace(/\r/g, "").trim();
+    if (!normalized || normalized.length === 0) return undefined;
+    if (input.validValues && !input.validValues.includes(normalized)) return undefined;
+    return normalized;
+  };
+
   if (!input.envKey) return undefined;
   if (input.kind === "config") {
     const resolved = resolveMessagingChannelConfigEnvValue(input.envKey, process.env);
-    if (resolved.value) return resolved.value;
+    const normalizedResolved = normalize(resolved.value);
+    if (normalizedResolved !== undefined) return normalizedResolved;
   }
-  const value = process.env[input.envKey];
-  const normalized = value?.replace(/\r/g, "").trim();
-  if (!normalized || normalized.length === 0) return undefined;
-  if (input.validValues && !input.validValues.includes(normalized)) return undefined;
-  return normalized;
+  return normalize(process.env[input.envKey]);
 }
🤖 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/messaging/compiler/manifest-compiler.ts` around lines 333 - 343, In
readInputEnvValue, config-resolved values returned early bypass the validValues
check; after calling resolveMessagingChannelConfigEnvValue(input.envKey,
process.env) assign its value to a local, normalize it the same way as env
lookup (strip \r and trim), reject if empty, and then apply
input.validValues.includes(normalized) before returning—i.e., replace the early
return of resolved.value with the same normalization and validValues gating used
for process.env[input.envKey] so both code paths enforce constraints (refer to
readInputEnvValue, resolveMessagingChannelConfigEnvValue, and
input.validValues).
🧹 Nitpick comments (3)
src/lib/actions/sandbox/rebuild.ts (1)

273-273: Run the rebuild-specific E2E suite for this behavior shift.

Please run the channels-stop-start-e2e workflow for this rebuild-path change to validate disabled-channel persistence and post-rebuild messaging reapply behavior.

As per coding guidelines, "src/lib/actions/sandbox/rebuild.ts ... E2E test recommendation: channels-stop-start-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 `@src/lib/actions/sandbox/rebuild.ts` at line 273, The rebuildSandbox change
needs its specific end-to-end validation: run the channels-stop-start-e2e
workflow to exercise rebuild-specific scenarios for disabled-channel persistence
and post-rebuild message reapply behavior; trigger that CI job and attach the
resulting logs to this PR, ensuring the rebuildSandbox function's behavior
around channel disable/persist and message reapply is confirmed by the E2E
results.

Source: Coding guidelines

Dockerfile (1)

413-550: Run the Dockerfile E2E subset before merge.

These changes move critical build behavior into manifest hook execution at image-build time, so unit tests alone won’t fully validate runtime delivery. Please run the recommended selective nightly E2E jobs for this path.

As per coding guidelines, Dockerfile changes are only fully testable with a real container build and should use the recommended selective 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 `@Dockerfile` around lines 413 - 550, The Dockerfile change runs
generate-openclaw-config.mts and run-openclaw-build-hooks.mts at build time
which requires a real container build to validate; before merging, perform the
Dockerfile E2E subset by building the image and running the repository's
selective nightly E2E jobs that exercise build-hook and config-generation paths
(specifically exercise run-openclaw-build-hooks.mts and
generate-openclaw-config.mts execution), verify the produced openclaw.json and
gateway token behavior in both root and non-root modes, and surface any failures
back to the PR so we can fix build-hook or config generation issues before
merge.

Source: Coding guidelines

src/lib/messaging/compiler/engines/template.ts (1)

161-197: 🏗️ Heavy lift

Break up resolveTemplateReference to reduce branching complexity

This resolver now centralizes many channel-specific branches, which makes it brittle for future additions. Split into a keyed resolver map (or per-channel resolver modules) and keep this function as a thin dispatcher.

As per coding guidelines, **/*.{js,ts,tsx,jsx}: "Keep function complexity low in JavaScript and TypeScript code."

🤖 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/messaging/compiler/engines/template.ts` around lines 161 - 197, The
resolveTemplateReference function has grown many channel-specific branches;
refactor it into a thin dispatcher that routes to per-channel resolver functions
or a keyed resolver map (e.g., a map keyed by the top-level token like
"discord", "telegramConfig", "wechatConfig", "slackConfig", "allowedIds",
"proxyUrl") and move the existing logic into those handlers (extract logic
currently in resolveTemplateReference for discord: discordGuilds,
discordAllowedUsers, discordRequireMention, for allowedIds:
resolveAllowedIdsTemplate usage, for telegramConfig: parseBoolean/stateValue,
for wechatConfig: stateValue, for slackConfig: slackAllowedChannels, and
proxyUrl) so resolveTemplateReference only picks the handler and returns
handler(reference, context) or the default template string; ensure semantics and
return types of RenderTemplateValue remain unchanged.

Source: Coding guidelines

🤖 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/config/manifest-hooks.ts`:
- Around line 83-90: The code currently treats any non-"json-fragment" render as
env-lines; update the logic in manifest-hooks.ts where render.kind is checked
(around the applyJsonRender/applyEnvRender calls) to explicitly handle allowed
kinds (e.g., "json-fragment" and "env-lines") and fail-closed for anything else:
if render.kind === "json-fragment" call applyJsonRender and push
appliedHooks/appliedTargets, else if render.kind === "env-lines" call
applyEnvRender and push appliedTargets, otherwise throw a descriptive Error (or
call the project’s error/assert utility) including the invalid render.kind and
render.target so schema drift/typos surface immediately.

In `@src/lib/messaging/compiler/engines/agent-render-engine.ts`:
- Around line 31-42: The default parameter creates an empty
MessagingHookRegistry which lacks required hooks (notably common.staticOutputs)
causing run-time failures when runMessagingHook is invoked; fix by ensuring the
passed-or-default registry contains the shared hooks before use — e.g., if hooks
is empty, register common.staticOutputs (and any other shared hooks) into the
MessagingHookRegistry instance used here (look for the hooks parameter,
MessagingHookRegistry, common.staticOutputs, renderHookForManifestEntry and
runMessagingHook) so render planning succeeds when callers omit hooks.

In `@test/e2e/docs/parity-inventory.generated.json`:
- Around line 8805-8807: The JSON entry's normalized_id is out of sync with its
text: update the "normalized_id" value for the object whose "text" is "M-W9:
Real WeChat token spliced into accounts/${WECHAT_ACCOUNT}.json — manifest seed
placeholder regression" so it reflects the manifest-seed regression semantics
(remove or replace the "seed.wechat.accounts.py" fragment and normalize to match
the text), ensuring the normalized_id string corresponds to the same source
semantics as the "text" field.

In `@test/onboard.test.ts`:
- Line 2718: Update the legacyMaxLines entry for the test file in the
test-file-size budget JSON: locate the JSON object key "test/onboard.test.ts" in
the test-file-size budget configuration and change its value from 4887 to 4879
so the legacyMaxLines matches the current file length (4879).

---

Outside diff comments:
In `@src/lib/messaging/compiler/manifest-compiler.ts`:
- Around line 333-343: In readInputEnvValue, config-resolved values returned
early bypass the validValues check; after calling
resolveMessagingChannelConfigEnvValue(input.envKey, process.env) assign its
value to a local, normalize it the same way as env lookup (strip \r and trim),
reject if empty, and then apply input.validValues.includes(normalized) before
returning—i.e., replace the early return of resolved.value with the same
normalization and validValues gating used for process.env[input.envKey] so both
code paths enforce constraints (refer to readInputEnvValue,
resolveMessagingChannelConfigEnvValue, and input.validValues).

In `@src/lib/onboard.ts`:
- Around line 3383-3387: The current guard uses activeMessagingChannels to
decide whether to set telegramConfig.requireMention, which drops the persisted
Telegram mention policy when providers are temporarily stopped; change the check
to use the persisted/configured channel set (e.g., enabledChannels or
enabledMessagingChannels / persisted messaging channels) instead of
activeMessagingChannels so computeTelegramRequireMention() runs whenever
Telegram is configured, not only when a provider is attached; update the block
around telegramConfig and computeTelegramRequireMention to key off that
persisted/enable set (ensure you reference telegramConfig,
computeTelegramRequireMention, and the enabledChannels/enabledMessagingChannels
variable) so TELEGRAM_REQUIRE_MENTION survives channels stop/start cycles.

In `@test/generate-openclaw-config.test.ts`:
- Around line 1-4: The recorded legacy "test-size" budget entry is off by one
(recorded 2106 vs actual 2105 lines) causing CI failures; update the legacy
test-size budget value to 2105 to match test/generate-openclaw-config.test.ts
current line count so codebase-growth-guardrails passes—locate the budget entry
named "legacy test-size" (or the test-size entry used by the
codebase-growth-guardrails config) and lower its numeric value from 2106 to
2105.

---

Nitpick comments:
In `@Dockerfile`:
- Around line 413-550: The Dockerfile change runs generate-openclaw-config.mts
and run-openclaw-build-hooks.mts at build time which requires a real container
build to validate; before merging, perform the Dockerfile E2E subset by building
the image and running the repository's selective nightly E2E jobs that exercise
build-hook and config-generation paths (specifically exercise
run-openclaw-build-hooks.mts and generate-openclaw-config.mts execution), verify
the produced openclaw.json and gateway token behavior in both root and non-root
modes, and surface any failures back to the PR so we can fix build-hook or
config generation issues before merge.

In `@src/lib/actions/sandbox/rebuild.ts`:
- Line 273: The rebuildSandbox change needs its specific end-to-end validation:
run the channels-stop-start-e2e workflow to exercise rebuild-specific scenarios
for disabled-channel persistence and post-rebuild message reapply behavior;
trigger that CI job and attach the resulting logs to this PR, ensuring the
rebuildSandbox function's behavior around channel disable/persist and message
reapply is confirmed by the E2E results.

In `@src/lib/messaging/compiler/engines/template.ts`:
- Around line 161-197: The resolveTemplateReference function has grown many
channel-specific branches; refactor it into a thin dispatcher that routes to
per-channel resolver functions or a keyed resolver map (e.g., a map keyed by the
top-level token like "discord", "telegramConfig", "wechatConfig", "slackConfig",
"allowedIds", "proxyUrl") and move the existing logic into those handlers
(extract logic currently in resolveTemplateReference for discord: discordGuilds,
discordAllowedUsers, discordRequireMention, for allowedIds:
resolveAllowedIdsTemplate usage, for telegramConfig: parseBoolean/stateValue,
for wechatConfig: stateValue, for slackConfig: slackAllowedChannels, and
proxyUrl) so resolveTemplateReference only picks the handler and returns
handler(reference, context) or the default template string; ensure semantics and
return types of RenderTemplateValue remain unchanged.
🪄 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: 4beb4b5f-e93c-4052-9c9a-7af56ccfdd8d

📥 Commits

Reviewing files that changed from the base of the PR and between ec408c8 and 59c6309.

📒 Files selected for processing (56)
  • Dockerfile
  • agents/hermes/Dockerfile
  • agents/hermes/config/build-env.ts
  • agents/hermes/config/hermes-config.ts
  • agents/hermes/config/hermes-env.ts
  • agents/hermes/config/manifest-hooks.ts
  • agents/hermes/config/messaging-config.ts
  • agents/hermes/generate-config.ts
  • agents/hermes/policy-additions.yaml
  • scripts/generate-openclaw-config.mts
  • scripts/lib/sandbox-init.sh
  • scripts/openclaw-build-messaging-plugins.py
  • scripts/run-openclaw-build-hooks.mts
  • scripts/seed-wechat-accounts.py
  • src/ext/wechat/qr.ts
  • src/lib/actions/sandbox/policy-channel.ts
  • src/lib/actions/sandbox/rebuild.ts
  • src/lib/adapters/openshell/client.ts
  • src/lib/adapters/openshell/runtime.ts
  • src/lib/messaging/applier/agent-config.ts
  • src/lib/messaging/applier/setup-applier.test.ts
  • src/lib/messaging/channels/discord/manifest.ts
  • src/lib/messaging/channels/manifests.test.ts
  • src/lib/messaging/channels/slack/manifest.ts
  • src/lib/messaging/channels/telegram/manifest.ts
  • src/lib/messaging/channels/wechat/manifest.ts
  • src/lib/messaging/channels/whatsapp/manifest.ts
  • src/lib/messaging/compiler/engines/agent-render-engine.ts
  • src/lib/messaging/compiler/engines/build-step-engine.ts
  • src/lib/messaging/compiler/engines/template.ts
  • src/lib/messaging/compiler/manifest-compiler.test.ts
  • src/lib/messaging/compiler/manifest-compiler.ts
  • src/lib/messaging/compiler/workflow-planner.test.ts
  • src/lib/messaging/hooks/common/index.ts
  • src/lib/messaging/hooks/common/static-outputs.ts
  • src/lib/messaging/hooks/common/token-paste.test.ts
  • src/lib/messaging/hooks/hook-runner.test.ts
  • src/lib/messaging/manifest/types.ts
  • src/lib/onboard.ts
  • src/lib/onboard/dockerfile-patch.test.ts
  • src/lib/onboard/dockerfile-patch.ts
  • src/lib/onboard/messaging-config.test.ts
  • src/lib/onboard/messaging-config.ts
  • src/lib/onboard/wechat-config.ts
  • src/lib/sandbox/build-context.ts
  • test/e2e/docs/parity-inventory.generated.json
  • test/e2e/test-messaging-providers.sh
  • test/generate-hermes-config.test.ts
  • test/generate-openclaw-config.test.ts
  • test/messaging-plan-test-helper.ts
  • test/onboard-messaging.test.ts
  • test/onboard.test.ts
  • test/run-openclaw-build-hooks.test.ts
  • test/sandbox-build-context.test.ts
  • test/sandbox-provisioning.test.ts
  • test/seed-wechat-accounts.test.ts
💤 Files with no reviewable changes (6)
  • src/lib/onboard/messaging-config.test.ts
  • scripts/openclaw-build-messaging-plugins.py
  • test/seed-wechat-accounts.test.ts
  • scripts/seed-wechat-accounts.py
  • agents/hermes/config/messaging-config.ts
  • agents/hermes/config/build-env.ts

Comment thread agents/hermes/config/manifest-hooks.ts Outdated
Comment thread src/lib/messaging/compiler/engines/agent-render-engine.ts Outdated
Comment thread test/e2e/docs/parity-inventory.generated.json Outdated
Comment thread test/onboard.test.ts
@sandl99 sandl99 marked this pull request as draft June 8, 2026 13:43
@copy-pr-bot

copy-pr-bot Bot commented Jun 8, 2026

Copy link
Copy Markdown

Auto-sync is disabled for draft pull requests in this repository. Workflows must be run manually.

Contributors can view more details about this message here.

Comment thread test/openclaw-config-render.test.ts Fixed
Comment thread src/lib/messaging/applier/build/messaging-build-applier.mts Fixed
Comment thread test/security-c2-dockerfile-injection.test.ts Fixed
Comment thread test/openclaw-config-render.test.ts Fixed
Comment thread src/lib/messaging/compiler/engines/agent-render-engine.ts Fixed
@NVIDIA NVIDIA deleted a comment from github-actions Bot Jun 8, 2026
@wscurran wscurran added area: messaging Messaging channels, bridges, manifests, or channel lifecycle refactor PR restructures code without intended behavior change labels Jun 8, 2026
@wscurran

wscurran commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

…ort, function or class'

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>

@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: 1

🧹 Nitpick comments (2)
Dockerfile (1)

559-597: Run the Dockerfile E2E subset before merge.

This path changes build-time messaging hook orchestration and post-install file generation, so it should be validated with the recommended nightly E2E job subset for Dockerfile-impacting changes.

As per coding guidelines: Dockerfile ... E2E test recommendation: cloud-e2e, sandbox-survival-e2e, hermes-e2e, rebuild-openclaw-e2e, openclaw-tui-chat-correlation-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 `@Dockerfile` around lines 559 - 597, This change updates build-time messaging
hook orchestration (the RUN node --experimental-strip-types
/src/lib/messaging/applier/build/messaging-build-applier.mts calls for --phase
agent-install and --phase post-agent-install and the openclaw plugins
install/enable/inspect steps), so before merging run the Dockerfile-impact E2E
subset: cloud-e2e, sandbox-survival-e2e, hermes-e2e, rebuild-openclaw-e2e, and
openclaw-tui-chat-correlation-e2e; verify the messaging post-agent-install
outputs are generated into the sandbox as expected, that openclaw plugins
install/enable/inspect succeeds and registers the /nemoclaw runtime command, and
that no network resolution occurred during the plugin install (confirm
NPM_CONFIG_OFFLINE behavior and pruned plugin-runtime-deps artifacts).

Source: Coding guidelines

agents/hermes/Dockerfile (1)

135-147: Run the Hermes E2E subset before merge.

These changes affect Hermes onboarding/build hooks and post-install render/build-file application, so they should be validated with the Hermes-focused nightly jobs.

As per coding guidelines: agents/hermes/** ... E2E test recommendation: hermes-e2e, hermes-inference-switch-e2e, hermes-discord-e2e, hermes-slack-e2e, hermes-onboard-security-posture-e2e, rebuild-hermes-e2e, 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/Dockerfile` around lines 135 - 147, These Dockerfile changes
touch Hermes onboarding and post-install hooks (see the RUN commands invoking
/src/lib/messaging/applier/build/messaging-build-applier.mts with --agent hermes
--phase agent-install and --phase post-agent-install and the nemoclaw plugin
copy into /sandbox/.hermes/plugins/nemoclaw/), so ensure the Hermes-focused E2E
subset is executed before merging by updating CI to include the recommended jobs
(hermes-e2e, hermes-inference-switch-e2e, hermes-discord-e2e, hermes-slack-e2e,
hermes-onboard-security-posture-e2e, rebuild-hermes-e2e,
rebuild-hermes-stale-base-e2e) in the PR/check pipeline or by scheduling a
blocking nightly run that validates these changes; modify the workflow matrix or
job list accordingly so these tests run against this Dockerfile change.

Source: Coding guidelines

🤖 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 `@src/lib/messaging/applier/build/messaging-build-applier.mts`:
- Around line 385-396: The current resolveAgentRenderTarget allows path
traversal via inputs like "~/.openclaw/../..." because it only checks prefixes;
fix by normalizing/ resolving the sliced subpath and validating it stays inside
the intended agent root before returning. In resolveAgentRenderTarget (variables
target, agent, home and throws MessagingBuildApplierError), compute the
agentRoot (join(home, ".openclaw") or join(home, ".hermes")), resolve the
candidate path against agentRoot and ensure the resolved path starts with
agentRoot (or that no path segment is ".."/contains upward traversal) and throw
MessagingBuildApplierError if validation fails; only return the resolved safe
path when the check passes.

---

Nitpick comments:
In `@agents/hermes/Dockerfile`:
- Around line 135-147: These Dockerfile changes touch Hermes onboarding and
post-install hooks (see the RUN commands invoking
/src/lib/messaging/applier/build/messaging-build-applier.mts with --agent hermes
--phase agent-install and --phase post-agent-install and the nemoclaw plugin
copy into /sandbox/.hermes/plugins/nemoclaw/), so ensure the Hermes-focused E2E
subset is executed before merging by updating CI to include the recommended jobs
(hermes-e2e, hermes-inference-switch-e2e, hermes-discord-e2e, hermes-slack-e2e,
hermes-onboard-security-posture-e2e, rebuild-hermes-e2e,
rebuild-hermes-stale-base-e2e) in the PR/check pipeline or by scheduling a
blocking nightly run that validates these changes; modify the workflow matrix or
job list accordingly so these tests run against this Dockerfile change.

In `@Dockerfile`:
- Around line 559-597: This change updates build-time messaging hook
orchestration (the RUN node --experimental-strip-types
/src/lib/messaging/applier/build/messaging-build-applier.mts calls for --phase
agent-install and --phase post-agent-install and the openclaw plugins
install/enable/inspect steps), so before merging run the Dockerfile-impact E2E
subset: cloud-e2e, sandbox-survival-e2e, hermes-e2e, rebuild-openclaw-e2e, and
openclaw-tui-chat-correlation-e2e; verify the messaging post-agent-install
outputs are generated into the sandbox as expected, that openclaw plugins
install/enable/inspect succeeds and registers the /nemoclaw runtime command, and
that no network resolution occurred during the plugin install (confirm
NPM_CONFIG_OFFLINE behavior and pruned plugin-runtime-deps artifacts).
🪄 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: 4959dcd2-ec8c-461d-8cd7-1045da67a1c3

📥 Commits

Reviewing files that changed from the base of the PR and between 59c6309 and 19ab1d1.

📒 Files selected for processing (20)
  • Dockerfile
  • agents/hermes/Dockerfile
  • agents/hermes/generate-config.ts
  • ci/test-file-size-budget.json
  • scripts/generate-openclaw-config.mts
  • src/lib/messaging/applier/build/messaging-build-applier.mts
  • src/lib/messaging/compiler/engines/agent-render-engine.ts
  • src/lib/messaging/compiler/manifest-compiler.ts
  • src/lib/onboard.ts
  • src/lib/sandbox/build-context.ts
  • test/e2e/docs/parity-inventory.generated.json
  • test/fetch-guard-patch-regression.test.ts
  • test/generate-hermes-config.test.ts
  • test/generate-openclaw-config.test.ts
  • test/helpers/messaging-plan-fixtures.ts
  • test/messaging-build-applier.test.ts
  • test/onboard-messaging.test.ts
  • test/sandbox-build-context.test.ts
  • test/sandbox-provisioning.test.ts
  • test/security-c2-dockerfile-injection.test.ts
✅ Files skipped from review due to trivial changes (1)
  • test/e2e/docs/parity-inventory.generated.json
🚧 Files skipped from review as they are similar to previous changes (5)
  • agents/hermes/generate-config.ts
  • test/generate-hermes-config.test.ts
  • src/lib/messaging/compiler/manifest-compiler.ts
  • test/onboard-messaging.test.ts
  • scripts/generate-openclaw-config.mts

Comment thread src/lib/messaging/applier/build/messaging-build-applier.mts

@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: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/lib/messaging/compiler/workflow-planner.ts (1)

74-80: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Validate sandbox/agent before deriving credential availability from sandbox entry plan.

Line 171 reads sandboxEntry.messaging.plan directly, bypassing the schema/sandbox/agent checks already enforced by readSandboxEntryPlan(...). This can import credential availability from a stale/mismatched plan and incorrectly skip credential enrollment during add-channel planning.

Suggested fix
-      credentialAvailability: mergeAvailability(
-        credentialAvailabilityFromPlan(existingPlan),
-        this.credentialAvailabilityFromSandboxEntry(
-          context.sandboxEntry,
-          [context.channelId],
-        ),
-        context.credentialAvailability,
-      ),
+      credentialAvailability: mergeAvailability(
+        credentialAvailabilityFromPlan(existingPlan),
+        this.credentialAvailabilityFromSandboxEntry(context, [context.channelId]),
+        context.credentialAvailability,
+      ),
@@
-  private credentialAvailabilityFromSandboxEntry(
-    sandboxEntry: MessagingWorkflowPlannerSandboxEntry | null | undefined,
+  private credentialAvailabilityFromSandboxEntry(
+    context: Pick<
+      MessagingWorkflowPlannerSandboxContext,
+      "sandboxName" | "agent" | "sandboxEntry"
+    >,
     channelIds: readonly MessagingChannelId[],
   ): MessagingCompilerCredentialAvailability | undefined {
-    const plan = sandboxEntry?.messaging?.plan;
+    const plan = readSandboxEntryPlan(context);
     if (!plan) return undefined;

Also applies to: 167-173

🤖 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/messaging/compiler/workflow-planner.ts` around lines 74 - 80,
credentialAvailabilityFromSandboxEntry is reading sandboxEntry.messaging.plan
directly (e.g., sandboxEntry.messaging.plan) which can pull stale or mismatched
plan data and bypass the validation done by readSandboxEntryPlan(...); change
the call sites that pass sandboxEntry directly into
credentialAvailabilityFromSandboxEntry so they first call
readSandboxEntryPlan(context.sandboxEntry) (or otherwise validate/normalize the
sandbox/agent via readSandboxEntryPlan) and then derive credential availability
from the validated plan object, ensuring
mergeAvailability(credentialAvailabilityFromPlan(...),
this.credentialAvailabilityFromSandboxEntry(...),
context.credentialAvailability) uses the validated plan rather than raw
sandboxEntry.messaging.plan.
🧹 Nitpick comments (3)
src/lib/actions/sandbox/policy-channel.ts (1)

199-200: Run the targeted messaging/onboarding E2E suites before merge.

Given policy-context refresh and conflict-path changes, run the listed Hermes/onboarding E2Es to validate end-to-end rebuild + state propagation behavior.

As per coding guidelines, onboarding and Hermes-affecting changes should run the recommended nightly E2E jobs for these paths.

Also applies to: 253-254, 1218-1219, 1358-1359, 1595-1596

🤖 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/actions/sandbox/policy-channel.ts` around lines 199 - 200, Run the
targeted Hermes and onboarding E2E suites before merging changes that touch
policy-context refresh and conflict-path behavior; specifically trigger the
onboarding and Hermes nightly E2E jobs to validate end-to-end rebuild and state
propagation after changes that call refreshSandboxPolicyContextFile (and related
changes around the same call sites referenced), and re-run the listed suites
covering the regions around refreshSandboxPolicyContextFile to confirm no
regressions in onboarding/Hermes flows.

Source: Coding guidelines

Dockerfile (1)

604-669: Run the Dockerfile E2E subset for this hook-migration path.

Given the build-time hook sequencing and plan transport changes, run the recommended E2E workflow subset before merge to validate real image behavior (build-time generated artifacts + runtime startup path).

As per coding guidelines, Dockerfile-layer changes should be validated with the recommended E2E jobs for container behavior.

🤖 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 604 - 669, Run the Dockerfile E2E subset to validate
the hook-migration path: exercise the build and runtime steps that involve the
OpenClaw agent and NemoClaw plugin (look for RUN steps invoking
/src/lib/messaging/applier/build/messaging-build-applier.mts with --phase
agent-install and --phase post-agent-install, the patch script
/usr/local/lib/nemoclaw/patch-openclaw-slack-deny-feedback.mts, and the openclaw
plugins install/enable/inspect sequence), ensuring the build-time generated
artifacts and runtime startup succeed under NPM_CONFIG_OFFLINE and the OpenClaw
OTEL conditional; if failures occur, capture logs from the image build and
container startup, reproduce locally with the same env vars
(NEMOCLAW_OPENCLAW_OTEL, OPENCLAW_VERSION, NPM_CONFIG_OFFLINE) and iterate until
the E2E subset passes before merging.

Source: Coding guidelines

agents/hermes/Dockerfile (1)

144-156: Run the Hermes E2E subset for hook-phase and onboarding safety.

This touches Hermes onboarding/config/render timing and post-install behavior, so validating with the Hermes-focused E2E jobs is worthwhile before merge.

As per coding guidelines, agents/hermes/** changes should be verified with the recommended Hermes E2E suite.

🤖 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/Dockerfile` around lines 144 - 156, This change affects Hermes
onboarding/render/post-agent-install hooks (see the node invocation of
messaging-build-applier.mts with --agent hermes and the nemoclaw plugin copy),
so before merging run the Hermes-focused E2E subset that exercises hook-phase
and onboarding/post-agent-install flows (i.e., CI job that validates
messaging-build-applier.mts --phase agent-install and --phase post-agent-install
and plugin install behavior) and ensure those tests pass; if failures appear,
reproduce locally against the same Dockerfile steps and fix timing/order or hook
scripts accordingly.

Source: Coding guidelines

🤖 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 `@src/lib/onboard.ts`:
- Around line 2891-2905: The loop that builds
reusableMessagingProviders/reusableMessagingChannels can add "slack" when only
the SLACK_APP_TOKEN is present, bypassing the bot-token guard later; update the
loop over messagingTokenDefs so that entries with envKey === "SLACK_APP_TOKEN"
are ignored for channel population (e.g., add a guard like if (envKey ===
"SLACK_APP_TOKEN") continue before computing channel), keeping the bot-token
gate in the reusable-provider path; ensure this change references the existing
variables/methods reusableMessagingProviders, reusableMessagingChannels,
messagingTokenDefs, and providerExistsInGateway so only fully-qualified Slack
(bot-token) providers can add the "slack" channel.

---

Outside diff comments:
In `@src/lib/messaging/compiler/workflow-planner.ts`:
- Around line 74-80: credentialAvailabilityFromSandboxEntry is reading
sandboxEntry.messaging.plan directly (e.g., sandboxEntry.messaging.plan) which
can pull stale or mismatched plan data and bypass the validation done by
readSandboxEntryPlan(...); change the call sites that pass sandboxEntry directly
into credentialAvailabilityFromSandboxEntry so they first call
readSandboxEntryPlan(context.sandboxEntry) (or otherwise validate/normalize the
sandbox/agent via readSandboxEntryPlan) and then derive credential availability
from the validated plan object, ensuring
mergeAvailability(credentialAvailabilityFromPlan(...),
this.credentialAvailabilityFromSandboxEntry(...),
context.credentialAvailability) uses the validated plan rather than raw
sandboxEntry.messaging.plan.

---

Nitpick comments:
In `@agents/hermes/Dockerfile`:
- Around line 144-156: This change affects Hermes
onboarding/render/post-agent-install hooks (see the node invocation of
messaging-build-applier.mts with --agent hermes and the nemoclaw plugin copy),
so before merging run the Hermes-focused E2E subset that exercises hook-phase
and onboarding/post-agent-install flows (i.e., CI job that validates
messaging-build-applier.mts --phase agent-install and --phase post-agent-install
and plugin install behavior) and ensure those tests pass; if failures appear,
reproduce locally against the same Dockerfile steps and fix timing/order or hook
scripts accordingly.

In `@Dockerfile`:
- Around line 604-669: Run the Dockerfile E2E subset to validate the
hook-migration path: exercise the build and runtime steps that involve the
OpenClaw agent and NemoClaw plugin (look for RUN steps invoking
/src/lib/messaging/applier/build/messaging-build-applier.mts with --phase
agent-install and --phase post-agent-install, the patch script
/usr/local/lib/nemoclaw/patch-openclaw-slack-deny-feedback.mts, and the openclaw
plugins install/enable/inspect sequence), ensuring the build-time generated
artifacts and runtime startup succeed under NPM_CONFIG_OFFLINE and the OpenClaw
OTEL conditional; if failures occur, capture logs from the image build and
container startup, reproduce locally with the same env vars
(NEMOCLAW_OPENCLAW_OTEL, OPENCLAW_VERSION, NPM_CONFIG_OFFLINE) and iterate until
the E2E subset passes before merging.

In `@src/lib/actions/sandbox/policy-channel.ts`:
- Around line 199-200: Run the targeted Hermes and onboarding E2E suites before
merging changes that touch policy-context refresh and conflict-path behavior;
specifically trigger the onboarding and Hermes nightly E2E jobs to validate
end-to-end rebuild and state propagation after changes that call
refreshSandboxPolicyContextFile (and related changes around the same call sites
referenced), and re-run the listed suites covering the regions around
refreshSandboxPolicyContextFile to confirm no regressions in onboarding/Hermes
flows.
🪄 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: 92d22fe6-ab7c-4299-bd60-46c59ef752b9

📥 Commits

Reviewing files that changed from the base of the PR and between 59c6309 and e9ec012.

📒 Files selected for processing (32)
  • Dockerfile
  • agents/hermes/Dockerfile
  • agents/hermes/config/build-env.ts
  • agents/hermes/config/hermes-config.ts
  • agents/hermes/generate-config.ts
  • ci/test-file-size-budget.json
  • scripts/generate-openclaw-config.mts
  • scripts/lib/sandbox-init.sh
  • src/lib/actions/sandbox/policy-channel.ts
  • src/lib/actions/sandbox/rebuild.ts
  • src/lib/messaging/applier/build/messaging-build-applier.mts
  • src/lib/messaging/applier/setup-applier.test.ts
  • src/lib/messaging/channels/discord/template-resolver.ts
  • src/lib/messaging/channels/index.ts
  • src/lib/messaging/channels/slack/template-resolver.ts
  • src/lib/messaging/channels/telegram/template-resolver.ts
  • src/lib/messaging/channels/template-resolver-utils.ts
  • src/lib/messaging/channels/template-resolver.ts
  • src/lib/messaging/channels/wechat/hooks/seed-openclaw-account.ts
  • src/lib/messaging/channels/wechat/template-resolver.ts
  • src/lib/messaging/channels/whatsapp/template-resolver.ts
  • src/lib/messaging/compiler/engines/agent-render-engine.ts
  • src/lib/messaging/compiler/engines/template.ts
  • src/lib/messaging/compiler/manifest-compiler.test.ts
  • src/lib/messaging/compiler/manifest-compiler.ts
  • src/lib/messaging/compiler/workflow-planner.test.ts
  • src/lib/messaging/compiler/workflow-planner.ts
  • src/lib/onboard.ts
  • src/lib/onboard/dockerfile-patch.test.ts
  • src/lib/onboard/dockerfile-patch.ts
  • src/lib/onboard/messaging-channel-setup.ts
  • src/lib/sandbox/build-context.ts
💤 Files with no reviewable changes (2)
  • src/lib/messaging/channels/wechat/hooks/seed-openclaw-account.ts
  • src/lib/actions/sandbox/rebuild.ts
✅ Files skipped from review due to trivial changes (1)
  • src/lib/messaging/channels/index.ts
🚧 Files skipped from review as they are similar to previous changes (8)
  • scripts/lib/sandbox-init.sh
  • src/lib/onboard/dockerfile-patch.ts
  • src/lib/messaging/compiler/engines/agent-render-engine.ts
  • src/lib/messaging/compiler/workflow-planner.test.ts
  • src/lib/messaging/applier/setup-applier.test.ts
  • agents/hermes/config/build-env.ts
  • agents/hermes/config/hermes-config.ts
  • scripts/generate-openclaw-config.mts

@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.

Caution

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/lib/messaging/compiler/workflow-planner.ts (1)

74-80: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Validate sandbox/agent before deriving credential availability from sandbox entry plan.

Line 171 reads sandboxEntry.messaging.plan directly, bypassing the schema/sandbox/agent checks already enforced by readSandboxEntryPlan(...). This can import credential availability from a stale/mismatched plan and incorrectly skip credential enrollment during add-channel planning.

Suggested fix
-      credentialAvailability: mergeAvailability(
-        credentialAvailabilityFromPlan(existingPlan),
-        this.credentialAvailabilityFromSandboxEntry(
-          context.sandboxEntry,
-          [context.channelId],
-        ),
-        context.credentialAvailability,
-      ),
+      credentialAvailability: mergeAvailability(
+        credentialAvailabilityFromPlan(existingPlan),
+        this.credentialAvailabilityFromSandboxEntry(context, [context.channelId]),
+        context.credentialAvailability,
+      ),
@@
-  private credentialAvailabilityFromSandboxEntry(
-    sandboxEntry: MessagingWorkflowPlannerSandboxEntry | null | undefined,
+  private credentialAvailabilityFromSandboxEntry(
+    context: Pick<
+      MessagingWorkflowPlannerSandboxContext,
+      "sandboxName" | "agent" | "sandboxEntry"
+    >,
     channelIds: readonly MessagingChannelId[],
   ): MessagingCompilerCredentialAvailability | undefined {
-    const plan = sandboxEntry?.messaging?.plan;
+    const plan = readSandboxEntryPlan(context);
     if (!plan) return undefined;

Also applies to: 167-173

🤖 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/messaging/compiler/workflow-planner.ts` around lines 74 - 80,
credentialAvailabilityFromSandboxEntry is reading sandboxEntry.messaging.plan
directly (e.g., sandboxEntry.messaging.plan) which can pull stale or mismatched
plan data and bypass the validation done by readSandboxEntryPlan(...); change
the call sites that pass sandboxEntry directly into
credentialAvailabilityFromSandboxEntry so they first call
readSandboxEntryPlan(context.sandboxEntry) (or otherwise validate/normalize the
sandbox/agent via readSandboxEntryPlan) and then derive credential availability
from the validated plan object, ensuring
mergeAvailability(credentialAvailabilityFromPlan(...),
this.credentialAvailabilityFromSandboxEntry(...),
context.credentialAvailability) uses the validated plan rather than raw
sandboxEntry.messaging.plan.
🧹 Nitpick comments (3)
src/lib/actions/sandbox/policy-channel.ts (1)

199-200: Run the targeted messaging/onboarding E2E suites before merge.

Given policy-context refresh and conflict-path changes, run the listed Hermes/onboarding E2Es to validate end-to-end rebuild + state propagation behavior.

As per coding guidelines, onboarding and Hermes-affecting changes should run the recommended nightly E2E jobs for these paths.

Also applies to: 253-254, 1218-1219, 1358-1359, 1595-1596

🤖 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/actions/sandbox/policy-channel.ts` around lines 199 - 200, Run the
targeted Hermes and onboarding E2E suites before merging changes that touch
policy-context refresh and conflict-path behavior; specifically trigger the
onboarding and Hermes nightly E2E jobs to validate end-to-end rebuild and state
propagation after changes that call refreshSandboxPolicyContextFile (and related
changes around the same call sites referenced), and re-run the listed suites
covering the regions around refreshSandboxPolicyContextFile to confirm no
regressions in onboarding/Hermes flows.

Source: Coding guidelines

Dockerfile (1)

604-669: Run the Dockerfile E2E subset for this hook-migration path.

Given the build-time hook sequencing and plan transport changes, run the recommended E2E workflow subset before merge to validate real image behavior (build-time generated artifacts + runtime startup path).

As per coding guidelines, Dockerfile-layer changes should be validated with the recommended E2E jobs for container behavior.

🤖 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 604 - 669, Run the Dockerfile E2E subset to validate
the hook-migration path: exercise the build and runtime steps that involve the
OpenClaw agent and NemoClaw plugin (look for RUN steps invoking
/src/lib/messaging/applier/build/messaging-build-applier.mts with --phase
agent-install and --phase post-agent-install, the patch script
/usr/local/lib/nemoclaw/patch-openclaw-slack-deny-feedback.mts, and the openclaw
plugins install/enable/inspect sequence), ensuring the build-time generated
artifacts and runtime startup succeed under NPM_CONFIG_OFFLINE and the OpenClaw
OTEL conditional; if failures occur, capture logs from the image build and
container startup, reproduce locally with the same env vars
(NEMOCLAW_OPENCLAW_OTEL, OPENCLAW_VERSION, NPM_CONFIG_OFFLINE) and iterate until
the E2E subset passes before merging.

Source: Coding guidelines

agents/hermes/Dockerfile (1)

144-156: Run the Hermes E2E subset for hook-phase and onboarding safety.

This touches Hermes onboarding/config/render timing and post-install behavior, so validating with the Hermes-focused E2E jobs is worthwhile before merge.

As per coding guidelines, agents/hermes/** changes should be verified with the recommended Hermes E2E suite.

🤖 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/Dockerfile` around lines 144 - 156, This change affects Hermes
onboarding/render/post-agent-install hooks (see the node invocation of
messaging-build-applier.mts with --agent hermes and the nemoclaw plugin copy),
so before merging run the Hermes-focused E2E subset that exercises hook-phase
and onboarding/post-agent-install flows (i.e., CI job that validates
messaging-build-applier.mts --phase agent-install and --phase post-agent-install
and plugin install behavior) and ensure those tests pass; if failures appear,
reproduce locally against the same Dockerfile steps and fix timing/order or hook
scripts accordingly.

Source: Coding guidelines

🤖 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 `@src/lib/onboard.ts`:
- Around line 2891-2905: The loop that builds
reusableMessagingProviders/reusableMessagingChannels can add "slack" when only
the SLACK_APP_TOKEN is present, bypassing the bot-token guard later; update the
loop over messagingTokenDefs so that entries with envKey === "SLACK_APP_TOKEN"
are ignored for channel population (e.g., add a guard like if (envKey ===
"SLACK_APP_TOKEN") continue before computing channel), keeping the bot-token
gate in the reusable-provider path; ensure this change references the existing
variables/methods reusableMessagingProviders, reusableMessagingChannels,
messagingTokenDefs, and providerExistsInGateway so only fully-qualified Slack
(bot-token) providers can add the "slack" channel.

---

Outside diff comments:
In `@src/lib/messaging/compiler/workflow-planner.ts`:
- Around line 74-80: credentialAvailabilityFromSandboxEntry is reading
sandboxEntry.messaging.plan directly (e.g., sandboxEntry.messaging.plan) which
can pull stale or mismatched plan data and bypass the validation done by
readSandboxEntryPlan(...); change the call sites that pass sandboxEntry directly
into credentialAvailabilityFromSandboxEntry so they first call
readSandboxEntryPlan(context.sandboxEntry) (or otherwise validate/normalize the
sandbox/agent via readSandboxEntryPlan) and then derive credential availability
from the validated plan object, ensuring
mergeAvailability(credentialAvailabilityFromPlan(...),
this.credentialAvailabilityFromSandboxEntry(...),
context.credentialAvailability) uses the validated plan rather than raw
sandboxEntry.messaging.plan.

---

Nitpick comments:
In `@agents/hermes/Dockerfile`:
- Around line 144-156: This change affects Hermes
onboarding/render/post-agent-install hooks (see the node invocation of
messaging-build-applier.mts with --agent hermes and the nemoclaw plugin copy),
so before merging run the Hermes-focused E2E subset that exercises hook-phase
and onboarding/post-agent-install flows (i.e., CI job that validates
messaging-build-applier.mts --phase agent-install and --phase post-agent-install
and plugin install behavior) and ensure those tests pass; if failures appear,
reproduce locally against the same Dockerfile steps and fix timing/order or hook
scripts accordingly.

In `@Dockerfile`:
- Around line 604-669: Run the Dockerfile E2E subset to validate the
hook-migration path: exercise the build and runtime steps that involve the
OpenClaw agent and NemoClaw plugin (look for RUN steps invoking
/src/lib/messaging/applier/build/messaging-build-applier.mts with --phase
agent-install and --phase post-agent-install, the patch script
/usr/local/lib/nemoclaw/patch-openclaw-slack-deny-feedback.mts, and the openclaw
plugins install/enable/inspect sequence), ensuring the build-time generated
artifacts and runtime startup succeed under NPM_CONFIG_OFFLINE and the OpenClaw
OTEL conditional; if failures occur, capture logs from the image build and
container startup, reproduce locally with the same env vars
(NEMOCLAW_OPENCLAW_OTEL, OPENCLAW_VERSION, NPM_CONFIG_OFFLINE) and iterate until
the E2E subset passes before merging.

In `@src/lib/actions/sandbox/policy-channel.ts`:
- Around line 199-200: Run the targeted Hermes and onboarding E2E suites before
merging changes that touch policy-context refresh and conflict-path behavior;
specifically trigger the onboarding and Hermes nightly E2E jobs to validate
end-to-end rebuild and state propagation after changes that call
refreshSandboxPolicyContextFile (and related changes around the same call sites
referenced), and re-run the listed suites covering the regions around
refreshSandboxPolicyContextFile to confirm no regressions in onboarding/Hermes
flows.
🪄 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: 92d22fe6-ab7c-4299-bd60-46c59ef752b9

📥 Commits

Reviewing files that changed from the base of the PR and between 59c6309 and e9ec012.

📒 Files selected for processing (32)
  • Dockerfile
  • agents/hermes/Dockerfile
  • agents/hermes/config/build-env.ts
  • agents/hermes/config/hermes-config.ts
  • agents/hermes/generate-config.ts
  • ci/test-file-size-budget.json
  • scripts/generate-openclaw-config.mts
  • scripts/lib/sandbox-init.sh
  • src/lib/actions/sandbox/policy-channel.ts
  • src/lib/actions/sandbox/rebuild.ts
  • src/lib/messaging/applier/build/messaging-build-applier.mts
  • src/lib/messaging/applier/setup-applier.test.ts
  • src/lib/messaging/channels/discord/template-resolver.ts
  • src/lib/messaging/channels/index.ts
  • src/lib/messaging/channels/slack/template-resolver.ts
  • src/lib/messaging/channels/telegram/template-resolver.ts
  • src/lib/messaging/channels/template-resolver-utils.ts
  • src/lib/messaging/channels/template-resolver.ts
  • src/lib/messaging/channels/wechat/hooks/seed-openclaw-account.ts
  • src/lib/messaging/channels/wechat/template-resolver.ts
  • src/lib/messaging/channels/whatsapp/template-resolver.ts
  • src/lib/messaging/compiler/engines/agent-render-engine.ts
  • src/lib/messaging/compiler/engines/template.ts
  • src/lib/messaging/compiler/manifest-compiler.test.ts
  • src/lib/messaging/compiler/manifest-compiler.ts
  • src/lib/messaging/compiler/workflow-planner.test.ts
  • src/lib/messaging/compiler/workflow-planner.ts
  • src/lib/onboard.ts
  • src/lib/onboard/dockerfile-patch.test.ts
  • src/lib/onboard/dockerfile-patch.ts
  • src/lib/onboard/messaging-channel-setup.ts
  • src/lib/sandbox/build-context.ts
💤 Files with no reviewable changes (2)
  • src/lib/messaging/channels/wechat/hooks/seed-openclaw-account.ts
  • src/lib/actions/sandbox/rebuild.ts
✅ Files skipped from review due to trivial changes (1)
  • src/lib/messaging/channels/index.ts
🚧 Files skipped from review as they are similar to previous changes (8)
  • scripts/lib/sandbox-init.sh
  • src/lib/onboard/dockerfile-patch.ts
  • src/lib/messaging/compiler/engines/agent-render-engine.ts
  • src/lib/messaging/compiler/workflow-planner.test.ts
  • src/lib/messaging/applier/setup-applier.test.ts
  • agents/hermes/config/build-env.ts
  • agents/hermes/config/hermes-config.ts
  • scripts/generate-openclaw-config.mts
🛑 Comments failed to post (1)
src/lib/onboard.ts (1)

2891-2905: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Keep Slack’s bot-token gate in the reusable-provider path.

This loop can add slack to reusableMessagingChannels when only ${sandboxName}-slack-app exists. That bypasses the existing guard at Lines 3311-3314, so the policy/registry can enable Slack and sandbox create will attach only the app provider. The bridge then starts with an incomplete Slack credential set.

Suggested fix
   const reusableMessagingProviders: string[] = [];
   const reusableMessagingChannels: string[] = [];
   if (enabledChannels != null) {
     for (const { name, envKey, token } of messagingTokenDefs) {
       if (token) continue;
       const channel =
         envKey === "SLACK_APP_TOKEN" ? "slack" : getMessagingChannelForEnvKey(envKey);
       if (!channel || !enabledChannels.includes(channel)) continue;
       if (!providerExistsInGateway(name)) continue;
       reusableMessagingProviders.push(name);
-      if (!reusableMessagingChannels.includes(channel)) {
+      const canReuseChannel =
+        envKey !== "SLACK_APP_TOKEN" ||
+        messagingTokenDefs.some(
+          (candidate) =>
+            candidate.envKey === "SLACK_BOT_TOKEN" &&
+            (!!candidate.token || providerExistsInGateway(candidate.name)),
+        );
+      if (canReuseChannel && !reusableMessagingChannels.includes(channel)) {
         reusableMessagingChannels.push(channel);
       }
     }
   }
🤖 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 2891 - 2905, The loop that builds
reusableMessagingProviders/reusableMessagingChannels can add "slack" when only
the SLACK_APP_TOKEN is present, bypassing the bot-token guard later; update the
loop over messagingTokenDefs so that entries with envKey === "SLACK_APP_TOKEN"
are ignored for channel population (e.g., add a guard like if (envKey ===
"SLACK_APP_TOKEN") continue before computing channel), keeping the bot-token
gate in the reusable-provider path; ensure this change references the existing
variables/methods reusableMessagingProviders, reusableMessagingChannels,
messagingTokenDefs, and providerExistsInGateway so only fully-qualified Slack
(bot-token) providers can add the "slack" channel.

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

Labels

area: messaging Messaging channels, bridges, manifests, or channel lifecycle refactor PR restructures code without intended behavior change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Phase 5: migrate messaging agent rendering and build inputs to manifests

3 participants