feat(scripts): add host-side Discord bridge#458
Conversation
📝 WalkthroughWalkthroughAdds a host-side Discord bridge: new Node.js bridge script using Changes
Sequence DiagramsequenceDiagram
participant User as Discord User
participant DiscordAPI as Discord API
participant Bridge as Discord Bridge
participant OpenShell as OpenShell CLI
participant SSH as SSH
participant Sandbox as NemoClaw Sandbox
participant Agent as OpenClaw Agent
User->>DiscordAPI: Send message to channel
DiscordAPI->>Bridge: messageCreate event
Bridge->>Bridge: validate guild / handle !reset / ensure sessionId
Bridge->>DiscordAPI: start typing indicator
Bridge->>OpenShell: request sandbox ssh-config
OpenShell-->>Bridge: ssh config
Bridge->>Bridge: write temp SSH config
Bridge->>SSH: ssh -F temp.conf run "nemoclaw-start openclaw agent" with env + --session-id
SSH->>Sandbox: execute command
Sandbox->>Agent: deliver message (model, API key, session)
Agent-->>Sandbox: return response stdout
Sandbox-->>SSH: return stdout/stderr
SSH-->>Bridge: collect output
Bridge->>Bridge: parse & chunk response
Bridge->>DiscordAPI: send response chunks
DiscordAPI-->>User: deliver messages
Bridge->>DiscordAPI: clear typing indicator
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 5
🧹 Nitpick comments (3)
docs/deployment/set-up-discord-bridge.md (3)
26-50: Add intro sentences under these H2 headings.
Prerequisites,Create a Discord Application and Bot, andInvite the Bot to Your Serverall jump straight into lists. The docs style guide wants each H2/H3 section to start with a short introductory sentence.As per coding guidelines, "Sections use H2 and H3, each starting with an introductory sentence."
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/deployment/set-up-discord-bridge.md` around lines 26 - 50, Add a one-sentence introductory line under each H2 heading "Prerequisites", "Create a Discord Application and Bot", and "Invite the Bot to Your Server" describing what the section covers (e.g., overview of required items, what creating the app/bot entails, and what inviting the bot accomplishes) so each section begins with a short context sentence per the docs style guide; keep the sentences concise and placed immediately before the existing lists/steps.
121-125: UseNext Stepshere.New docs pages are supposed to end with a
Next Stepssection, and this H2 should also open with a brief intro sentence before the links.As per coding guidelines, "A 'Next Steps' section at the bottom links to related pages," and "Sections use H2 and H3, each starting with an introductory sentence."
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/deployment/set-up-discord-bridge.md` around lines 121 - 125, Rename the H2 titled "Related Topics" to "Next Steps" and add a one-sentence introductory lead immediately below that H2 (e.g., "Next steps and related documentation to help you continue setup:") before the existing bullet links; keep the three existing links unchanged and retain the H2 level formatting so the section matches the documentation guidelines and the rest of the page structure.
39-39: Replace the em dash in this note.LLM pattern detected. The dash here is acting as sentence punctuation; use a period instead.
As per coding guidelines, "Excessive em dashes. One per paragraph is fine; multiple per paragraph or em dashes used instead of commas/periods should be flagged."
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/deployment/set-up-discord-bridge.md` at line 39, The sentence "Store it securely — Discord does not show it again." uses an em dash as sentence punctuation; replace the em dash with a period and adjust spacing so it reads "Store it securely. Discord does not show it again." to comply with the guideline against excessive em dashes.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@docs/deployment/set-up-discord-bridge.md`:
- Around line 51-65: The docs only show exporting DISCORD_BOT_TOKEN but omits
NVIDIA_API_KEY which causes `nemoclaw start` to fail; update the "Set the
Environment Variable" section to instruct users to also export NVIDIA_API_KEY
(e.g., export NVIDIA_API_KEY=<your-key>) before running `nemoclaw start`, and
add a brief note mentioning that the Discord bridge depends on NVIDIA_API_KEY so
startup will error if it is missing (references: NVIDIA_API_KEY, the `nemoclaw
start` command and the discord bridge startup).
In `@scripts/discord-bridge.js`:
- Line 156: The current console.log in scripts/discord-bridge.js prints full
chat transcripts (using message.guild.name, message.channel.name,
message.author.username and content); change this to avoid logging raw user
messages by either (a) logging only non-sensitive metadata (e.g., guild id,
channel id, author id/username and message length) or (b) gating full-text logs
behind an explicit debug flag (e.g., process.env.DEBUG_DISCORD === 'true') so
that content is never written to logs by default; update both occurrences that
print message content (the console.log at the message output line and the
similar log at the other noted line) and ensure any debug-path still redacts or
escapes sensitive fields unless the debug flag is set.
- Around line 56-57: Concurrent calls to runAgentInSandbox() reuse the same
dc-ch-<channelId> session and the same /tmp/nemoclaw-dc-ssh-<sessionId>.conf
which can cause one call to delete or overwrite the SSH config while another is
using it; fix by serializing requests per channel or making the config unique
per invocation. Implement a channel-level mutex/queue keyed by channelId around
runAgentInSandbox() usage (or the code that writes/deletes confPath) so only one
request for a given channel runs at a time, or change the confPath generation to
include a unique suffix (e.g., timestamp+PID+random) so each invocation writes a
distinct temp file and cleans up its own file without affecting others; update
all spots that write/remove the SSH config (the code that sets confPath and
calls writeFileSync/unlink) to use the mutex or unique-per-call path
accordingly.
- Line 35: The script's SANDBOX constant uses a different default ("nemoclaw")
than the service launcher; update the SANDBOX fallback in
scripts/discord-bridge.js so it matches the launcher by using "default" instead
of "nemoclaw" (i.e., change the SANDBOX assignment that references
process.env.SANDBOX_NAME to fall back to "default") to ensure both tools target
the same sandbox when SANDBOX_NAME is unset.
- Around line 147-165: The reset path deletes activeSessions but a new sessionId
is always recomputed as `ch-${channelId}` regardless of the map, so reset
doesn't clear downstream history; change the logic so you first check
activeSessions.get(channelId) and reuse that sessionId if present, otherwise
create and set sessionId = `ch-${channelId}` only when absent (use
activeSessions.get(channelId) and activeSessions.set(channelId, sessionId)
around the existing `sessionId` usage), ensuring the !reset branch truly clears
the stored session by removing the map entry and letting the next message create
a fresh entry.
---
Nitpick comments:
In `@docs/deployment/set-up-discord-bridge.md`:
- Around line 26-50: Add a one-sentence introductory line under each H2 heading
"Prerequisites", "Create a Discord Application and Bot", and "Invite the Bot to
Your Server" describing what the section covers (e.g., overview of required
items, what creating the app/bot entails, and what inviting the bot
accomplishes) so each section begins with a short context sentence per the docs
style guide; keep the sentences concise and placed immediately before the
existing lists/steps.
- Around line 121-125: Rename the H2 titled "Related Topics" to "Next Steps" and
add a one-sentence introductory lead immediately below that H2 (e.g., "Next
steps and related documentation to help you continue setup:") before the
existing bullet links; keep the three existing links unchanged and retain the H2
level formatting so the section matches the documentation guidelines and the
rest of the page structure.
- Line 39: The sentence "Store it securely — Discord does not show it again."
uses an em dash as sentence punctuation; replace the em dash with a period and
adjust spacing so it reads "Store it securely. Discord does not show it again."
to comply with the guideline against excessive em dashes.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: d0b12b56-0206-42d3-9905-66be8b7e7114
📒 Files selected for processing (5)
docs/deployment/set-up-discord-bridge.mddocs/index.mdpackage.jsonscripts/discord-bridge.jsscripts/start-services.sh
There was a problem hiding this comment.
Actionable comments posted: 3
♻️ Duplicate comments (2)
scripts/discord-bridge.js (2)
188-200:⚠️ Potential issue | 🟠 MajorSerialize same-channel requests before reusing
sessionId.Lines 188-197 still let two messages in the same channel call
runAgentInSandbox()concurrently against the samesessionId. The unique temp-file path fixed the config-file collision, but replies can still arrive out of order and the shared downstream history can interleave. Add a channel-scoped queue or mutex around the agent run.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@scripts/discord-bridge.js` around lines 188 - 200, Concurrent calls to runAgentInSandbox using the same sessionId can interleave history and cause out-of-order replies; add channel-scoped serialization so only one runAgentInSandbox runs per channel at a time (e.g., a Map keyed by channelId holding a Promise/lock or a simple async queue). Wrap the section that obtains sessionId and calls runAgentInSandbox/sendChunked (references: activeSessions.get(channelId), sessionId, runAgentInSandbox, sendChunked, typingInterval) in that per-channel mutex/queue so subsequent messages for the same channel await the prior agent run finishing (including clearInterval and sendChunked) before starting; ensure the typingInterval is still cleared on completion or error and that errors release the lock so the queue can proceed.
168-188:⚠️ Potential issue | 🟠 MajorUse a stable per-channel session ID by default.
Line 186 timestamps every first-seen channel, which makes the downstream session process-lifetime-scoped instead of channel-scoped. After a bridge restart, the same Discord channel gets a new
dc-...session and loses history even though nobody ran!reset. Keepch-${channelId}as the default, and mint the timestamped variant only in the reset branch.💡 Minimal fix
if (content === "!reset") { - activeSessions.delete(channelId); + activeSessions.set(channelId, `ch-${channelId}-${Date.now()}`); await message.reply("Session reset."); return; } @@ - if (!activeSessions.has(channelId)) { - activeSessions.set(channelId, `ch-${channelId}-${Date.now()}`); - } - const sessionId = activeSessions.get(channelId); + const sessionId = activeSessions.get(channelId) ?? `ch-${channelId}`; + activeSessions.set(channelId, sessionId);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@scripts/discord-bridge.js` around lines 168 - 188, The session IDs are currently created with a timestamp causing sessions to change after restarts; change the default creation in the session-reuse block (where activeSessions.set(channelId, `ch-${channelId}-${Date.now()}`) and sessionId is read) to a stable per-channel id like `ch-${channelId}`, and only create a timestamped id when the user explicitly resets (modify the "!reset" branch that currently calls activeSessions.delete(channelId) to instead set a new timestamped id, e.g., `ch-${channelId}-${Date.now()}`, or delete then immediately set the timestamped id so downstream history is only lost on explicit reset).
🧹 Nitpick comments (1)
docs/deployment/set-up-discord-bridge.md (1)
69-69: Replace these colon-ended lead-ins with period-ended sentences.Lines 69, 84, 102, 112, and 123 are full sentences that end with colons before command blocks. The docs style guide wants sentences to end with periods and reserves colons for lists. As per coding guidelines, "Every sentence must end with a period." and "Colons should only introduce a list."
Also applies to: 84-84, 102-102, 112-112, 123-123
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/deployment/set-up-discord-bridge.md` at line 69, Replace the colon-terminated lead-in sentences with period-terminated sentences for each instance (e.g., change "Start the Discord bridge and other auxiliary services:" to "Start the Discord bridge and other auxiliary services.") — update the same style for the other identified strings on lines that currently read like full sentences ending with a colon (the lead-ins at the same locations as "Start the Discord bridge and other auxiliary services:") so every sentence ends with a period and colons are only used for lists.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@docs/deployment/set-up-discord-bridge.md`:
- Around line 104-106: The unlabeled fenced code block containing "!reset"
should either be converted to an inline code span (`!reset`) or have an explicit
language added to the fence (e.g., ```text) to satisfy markdownlint; update the
fenced block around the "!reset" token to use a language identifier like "text"
or collapse it to inline code.
- Around line 57-65: Add documentation for the SANDBOX_NAME and NEMOCLAW_MODEL
environment variables in the "Set the Environment Variables" section: describe
that SANDBOX_NAME selects the target sandbox (and state the default if any) and
that NEMOCLAW_MODEL selects the model to use (and state the default model), show
example export commands for both (e.g., export SANDBOX_NAME=<name> and export
NEMOCLAW_MODEL=<model>), and note that the bridge will read these variables at
startup so operators can target a non-default sandbox or model.
In `@scripts/discord-bridge.js`:
- Around line 145-151: The Client is created without an allowedMentions policy
so bot output can trigger unintended pings; update the new Client instantiation
(the Client constructor where const client = new Client(...)) to include an
allowedMentions option that disables parsing (e.g., allowedMentions: { parse:
[], repliedUser: false }) so user/role/@everyone/@here mentions are not
automatically parsed by default.
---
Duplicate comments:
In `@scripts/discord-bridge.js`:
- Around line 188-200: Concurrent calls to runAgentInSandbox using the same
sessionId can interleave history and cause out-of-order replies; add
channel-scoped serialization so only one runAgentInSandbox runs per channel at a
time (e.g., a Map keyed by channelId holding a Promise/lock or a simple async
queue). Wrap the section that obtains sessionId and calls
runAgentInSandbox/sendChunked (references: activeSessions.get(channelId),
sessionId, runAgentInSandbox, sendChunked, typingInterval) in that per-channel
mutex/queue so subsequent messages for the same channel await the prior agent
run finishing (including clearInterval and sendChunked) before starting; ensure
the typingInterval is still cleared on completion or error and that errors
release the lock so the queue can proceed.
- Around line 168-188: The session IDs are currently created with a timestamp
causing sessions to change after restarts; change the default creation in the
session-reuse block (where activeSessions.set(channelId,
`ch-${channelId}-${Date.now()}`) and sessionId is read) to a stable per-channel
id like `ch-${channelId}`, and only create a timestamped id when the user
explicitly resets (modify the "!reset" branch that currently calls
activeSessions.delete(channelId) to instead set a new timestamped id, e.g.,
`ch-${channelId}-${Date.now()}`, or delete then immediately set the timestamped
id so downstream history is only lost on explicit reset).
---
Nitpick comments:
In `@docs/deployment/set-up-discord-bridge.md`:
- Line 69: Replace the colon-terminated lead-in sentences with period-terminated
sentences for each instance (e.g., change "Start the Discord bridge and other
auxiliary services:" to "Start the Discord bridge and other auxiliary
services.") — update the same style for the other identified strings on lines
that currently read like full sentences ending with a colon (the lead-ins at the
same locations as "Start the Discord bridge and other auxiliary services:") so
every sentence ends with a period and colons are only used for lists.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 29c888da-c67e-4da1-a9bd-0912cfeb46d0
📒 Files selected for processing (2)
docs/deployment/set-up-discord-bridge.mdscripts/discord-bridge.js
|
Thanks for adding a host-side Discord bridge, this will enable more flexible communication options for our users. |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@docs/deployment/set-up-discord-bridge.md`:
- Line 43: The line containing "Store it securely. Discord does not show it
again." has two sentences on one line; split this into two separate lines so
each sentence is on its own line (i.e., one line "Store it securely." and the
next line "Discord does not show it again.") to comply with the
one-sentence-per-line formatting rule.
- Line 133: Replace the sentence fragment "To stop the Discord bridge and all
other auxiliary services." with a complete sentence that ends with a period; for
example, change it to "To stop the Discord bridge and all other auxiliary
services, run the following commands." or "Use this section to stop the Discord
bridge and all other auxiliary services." Ensure the updated line is a full
sentence and fits the surrounding section's tone and instructions.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 3785e035-f95c-4d1b-971c-51621455a16f
📒 Files selected for processing (2)
docs/deployment/set-up-discord-bridge.mdscripts/discord-bridge.js
🚧 Files skipped from review as they are similar to previous changes (1)
- scripts/discord-bridge.js
There was a problem hiding this comment.
🧹 Nitpick comments (2)
docs/deployment/set-up-discord-bridge.md (2)
75-76: Replace inline colon punctuation in default-value clauses.
(default: ...)uses a colon as general punctuation, which this style guide disallows outside list introductions.As per coding guidelines, "Colons should only introduce a list. Flag colons used as general punctuation between clauses."
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/deployment/set-up-discord-bridge.md` around lines 75 - 76, The default-value clauses for SANDBOX_NAME and NEMOCLAW_MODEL use a disallowed inline colon "(default: `...`)"; update the text for SANDBOX_NAME and NEMOCLAW_MODEL to remove the colon (e.g., "(default `default`)" and "(default `nvidia/nemotron-3-super-120b-a12b`)" or rewrite as "default is `...`") so the parentheses no longer contain a colon used as general punctuation.
91-91: Use active voice for the startup condition.“The Discord bridge starts only when the
DISCORD_BOT_TOKENenvironment variable is set.” uses passive voice; rephrase with an explicit subject (for example, “when you set ...”).As per coding guidelines, "Active voice required. Flag passive constructions."
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/deployment/set-up-discord-bridge.md` at line 91, Rephrase the passive startup sentence into active voice; replace "The Discord bridge starts only when the `DISCORD_BOT_TOKEN` environment variable is set." with an explicit subject instruction such as "Set the `DISCORD_BOT_TOKEN` environment variable to start the Discord bridge." to comply with the Active voice required guideline.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@docs/deployment/set-up-discord-bridge.md`:
- Around line 75-76: The default-value clauses for SANDBOX_NAME and
NEMOCLAW_MODEL use a disallowed inline colon "(default: `...`)"; update the text
for SANDBOX_NAME and NEMOCLAW_MODEL to remove the colon (e.g., "(default
`default`)" and "(default `nvidia/nemotron-3-super-120b-a12b`)" or rewrite as
"default is `...`") so the parentheses no longer contain a colon used as general
punctuation.
- Line 91: Rephrase the passive startup sentence into active voice; replace "The
Discord bridge starts only when the `DISCORD_BOT_TOKEN` environment variable is
set." with an explicit subject instruction such as "Set the `DISCORD_BOT_TOKEN`
environment variable to start the Discord bridge." to comply with the Active
voice required guideline.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: e63eaca8-306f-4d50-b191-aeafdd16ada3
📒 Files selected for processing (1)
docs/deployment/set-up-discord-bridge.md
There was a problem hiding this comment.
🧹 Nitpick comments (1)
docs/deployment/set-up-discord-bridge.md (1)
6-8: Fix product-name casing in frontmatter keywords and tags.Line 6 and Line 8 use lowercase product names (
nemoclaw,openclaw,openshell). Please update these toNemoClaw,OpenClaw, andOpenShellfor terminology consistency across docs metadata and prose.As per coding guidelines, "NemoClaw, OpenClaw, and OpenShell must use correct casing."
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/deployment/set-up-discord-bridge.md` around lines 6 - 8, Update the frontmatter entries "keywords" and "tags" to use the correct product-name casing: replace "nemoclaw" with "NemoClaw", "openclaw" with "OpenClaw", and "openshell" with "OpenShell" in the values for the keywords and tags arrays so that the metadata keys keywords and tags contain the correctly cased product names.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@docs/deployment/set-up-discord-bridge.md`:
- Around line 6-8: Update the frontmatter entries "keywords" and "tags" to use
the correct product-name casing: replace "nemoclaw" with "NemoClaw", "openclaw"
with "OpenClaw", and "openshell" with "OpenShell" in the values for the keywords
and tags arrays so that the metadata keys keywords and tags contain the
correctly cased product names.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 28febc8f-59c8-44d3-bc68-71699ded0834
📒 Files selected for processing (1)
docs/deployment/set-up-discord-bridge.md
|
@coderabbitai resume |
✅ Actions performedReviews resumed. |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@docs/deployment/set-up-discord-bridge.md`:
- Around line 75-76: Split the two sentences about SANDBOX_NAME and
NEMOCLAW_MODEL so each sentence is on its own line: ensure the sentence
describing `SANDBOX_NAME` ("`SANDBOX_NAME` selects which sandbox the bridge
connects to. The default is `default`.") is two separate lines, and do the same
for `NEMOCLAW_MODEL` ("`NEMOCLAW_MODEL` sets the model the agent uses for
inference. The default is `nvidia/nemotron-3-super-120b-a12b`.") so every
sentence appears on its own line for readable diffs.
🪄 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: Pro
Run ID: 787db70d-fc34-4424-be48-be5c9a48d1b0
📒 Files selected for processing (1)
docs/deployment/set-up-discord-bridge.md
| `SANDBOX_NAME` selects which sandbox the bridge connects to. The default is `default`. | ||
| `NEMOCLAW_MODEL` sets the model the agent uses for inference. The default is `nvidia/nemotron-3-super-120b-a12b`. |
There was a problem hiding this comment.
Split into one sentence per line.
Lines 75 and 76 each contain two sentences on the same line, violating the formatting rule requiring one sentence per line for readable diffs. As per coding guidelines, "One sentence per line in source (makes diffs readable). Flag paragraphs where multiple sentences appear on the same line."
📝 Proposed fix
-`SANDBOX_NAME` selects which sandbox the bridge connects to. The default is `default`.
-`NEMOCLAW_MODEL` sets the model the agent uses for inference. The default is `nvidia/nemotron-3-super-120b-a12b`.
+`SANDBOX_NAME` selects which sandbox the bridge connects to.
+The default is `default`.
+`NEMOCLAW_MODEL` sets the model the agent uses for inference.
+The default is `nvidia/nemotron-3-super-120b-a12b`.📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| `SANDBOX_NAME` selects which sandbox the bridge connects to. The default is `default`. | |
| `NEMOCLAW_MODEL` sets the model the agent uses for inference. The default is `nvidia/nemotron-3-super-120b-a12b`. | |
| `SANDBOX_NAME` selects which sandbox the bridge connects to. | |
| The default is `default`. | |
| `NEMOCLAW_MODEL` sets the model the agent uses for inference. | |
| The default is `nvidia/nemotron-3-super-120b-a12b`. |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@docs/deployment/set-up-discord-bridge.md` around lines 75 - 76, Split the two
sentences about SANDBOX_NAME and NEMOCLAW_MODEL so each sentence is on its own
line: ensure the sentence describing `SANDBOX_NAME` ("`SANDBOX_NAME` selects
which sandbox the bridge connects to. The default is `default`.") is two
separate lines, and do the same for `NEMOCLAW_MODEL` ("`NEMOCLAW_MODEL` sets the
model the agent uses for inference. The default is
`nvidia/nemotron-3-super-120b-a12b`.") so every sentence appears on its own line
for readable diffs.
* add guidance for OpenAI-compatible cloud providers * add provider list and xref link * add xref * add provider name value column
Add scripts/discord-bridge.js following the same architecture as the Telegram bridge. Runs on the host because the sandbox proxy does not support CONNECT tunneling for WebSockets, which the Discord gateway requires (see NVIDIA#409). - Per-channel session continuity via channel-scoped session IDs - Message chunking at Discord's 2000-character limit - NEMOCLAW_MODEL and SANDBOX_NAME env var support - ALLOWED_GUILD_IDS for access control - !reset command to clear a channel session - Typing indicator while the agent runs Updates start-services.sh to start/stop the Discord bridge alongside the Telegram bridge when DISCORD_BOT_TOKEN is set. Adds docs/deployment/set-up-discord-bridge.md with setup instructions for creating a Discord application, inviting the bot, and configuring access control. Adds discord.js ^14.16.3 to package.json dependencies. Closes NVIDIA#422.
scripts/discord-bridge.js:
- Fix SANDBOX default to "default" to match start-services.sh
- Fix session ID logic: reuse stored ID per channel, use timestamped
unique ID so !reset truly starts a fresh session
- Fix SSH config race: use unique confPath per invocation
(timestamp + random suffix) to avoid concurrent call collisions
- Redact message content from logs by default; gate full-text
logging behind DEBUG_DISCORD=true env var
- Add JSDoc to runAgentInSandbox() and sendChunked()
docs/deployment/set-up-discord-bridge.md:
- Add NVIDIA_API_KEY export to environment variables section
- Add intro sentence under Prerequisites, Create a Bot, Invite Bot H2s
- Rename "Related Topics" to "Next Steps" with intro sentence
- Replace em dash with period ("Store it securely. Discord...")
scripts/discord-bridge.js:
- Add allowedMentions: { parse: [], repliedUser: false } to Client
constructor to prevent unintended pings from bot responses
- Add per-channel serialization queue (channelQueues Map) so only one
agent call runs per channel at a time, preventing interleaved replies
- Revert session ID to stable ch-<channelId> by default so sessions
survive restarts; !reset now sets a timestamped ID to force fresh history
- Add JSDoc for enqueueForChannel()
docs/deployment/set-up-discord-bridge.md:
- Add SANDBOX_NAME and NEMOCLAW_MODEL optional env var documentation
- Fix bare code block for !reset to use text language tag
- Replace colon with period on lead-in sentences before code blocks
Split the two-sentence token note onto separate lines and complete the sentence fragment in the Stop the Services section. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace "(default: `...`)" with "The default is `...`" on the SANDBOX_NAME and NEMOCLAW_MODEL description lines, and rephrase the passive startup condition sentence to active voice. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Use correct casing — NemoClaw, OpenClaw, OpenShell — in the keywords and tags frontmatter arrays. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
f0dbb20 to
6457de0
Compare
There was a problem hiding this comment.
♻️ Duplicate comments (1)
docs/deployment/set-up-discord-bridge.md (1)
75-76:⚠️ Potential issue | 🟡 MinorSplit into one sentence per line.
Lines 75 and 76 each contain two sentences on the same line, which violates the formatting rule requiring one sentence per line for readable diffs. As per coding guidelines, "One sentence per line in source (makes diffs readable). Flag paragraphs where multiple sentences appear on the same line."
📝 Proposed fix
-`SANDBOX_NAME` selects which sandbox the bridge connects to. The default is `default`. -`NEMOCLAW_MODEL` sets the model the agent uses for inference. The default is `nvidia/nemotron-3-super-120b-a12b`. +`SANDBOX_NAME` selects which sandbox the bridge connects to. +The default is `default`. +`NEMOCLAW_MODEL` sets the model the agent uses for inference. +The default is `nvidia/nemotron-3-super-120b-a12b`.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/deployment/set-up-discord-bridge.md` around lines 75 - 76, The two lines mentioning SANDBOX_NAME and NEMOCLAW_MODEL contain two sentences each; split each into separate lines so there is one sentence per line. Locate the lines that reference SANDBOX_NAME and NEMOCLAW_MODEL and break them so the sentence about what the variable selects/sets is on one line and the sentence about its default value is on the following line (e.g., for SANDBOX_NAME: one line "SANDBOX_NAME selects which sandbox the bridge connects to." and next line "The default is `default`."; similarly for NEMOCLAW_MODEL).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In `@docs/deployment/set-up-discord-bridge.md`:
- Around line 75-76: The two lines mentioning SANDBOX_NAME and NEMOCLAW_MODEL
contain two sentences each; split each into separate lines so there is one
sentence per line. Locate the lines that reference SANDBOX_NAME and
NEMOCLAW_MODEL and break them so the sentence about what the variable
selects/sets is on one line and the sentence about its default value is on the
following line (e.g., for SANDBOX_NAME: one line "SANDBOX_NAME selects which
sandbox the bridge connects to." and next line "The default is `default`.";
similarly for NEMOCLAW_MODEL).
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 1a458628-681d-4348-acb4-043c567040da
📒 Files selected for processing (5)
docs/deployment/set-up-discord-bridge.mddocs/index.mdpackage.jsonscripts/discord-bridge.jsscripts/start-services.sh
✅ Files skipped from review due to trivial changes (3)
- docs/index.md
- package.json
- scripts/discord-bridge.js
🚧 Files skipped from review as they are similar to previous changes (1)
- scripts/start-services.sh
|
Thanks for the Discord bridge implementation. There's overlapping work in #422 from another contributor — before we can review either PR, it would help to align on a single approach. Could you rebase against main, review #422, and coordinate with that contributor on which implementation to move forward? Happy to facilitate if useful. |
|
Thanks, I’ll rebase #422 onto the current main and review #458 for overlap. From an initial comparison, the overlap looks substantial: both PRs add a host-side Discord bridge using discord.js, integrate it with the service startup flow, add deployment/setup docs, and maintain channel-scoped session continuity. One notable difference is that #422 extends beyond the bridge implementation itself by also updating the deploy/CLI flow for forwarding the Discord bot token, while #458 appears to focus more on Discord-specific runtime refinements such as reset handling, typing indicators, message chunking, allowlisting, and queueing/safety follow-ups. Once I’ve rebased and rechecked against main, I’m happy to coordinate on a single landing path with @phanisaimunipalli. |
|
Thanks for this — a host-side Discord bridge is a frequently requested integration. We're doing an evaluation of the Discord bridge approach before committing to a merge path, as there's also a competing implementation in #422. We'll be reviewing both PRs together to decide on direction. We'll follow up here once we have a clearer picture. No action needed on your end for now — we'll reach out if we need more information. |
|
Thanks for contributing this. The underlying limitation this PR worked around — the sandbox proxy not supporting CONNECT tunneling for WebSocket connections to Closing as superseded. Feel free to reopen if you see gaps in the current Discord channel support. |
Summary
Adds a host-side Discord bridge for NemoClaw, following the same architecture as the existing Telegram bridge.
A host-side bridge is required because the sandbox proxy does not support CONNECT tunneling for WebSockets, which the Discord gateway (
gateway.discord.gg) requires. This is the same constraint described in #409.Changes
scripts/discord-bridge.js— Discord bot that forwards channel messages to the OpenClaw agent via SSH and posts responses back. Usesdiscord.jsv14.scripts/start-services.sh— Updated to start/stop the Discord bridge alongside the Telegram bridge whenDISCORD_BOT_TOKENis set.docs/deployment/set-up-discord-bridge.md— Step-by-step setup guide covering bot creation, intents, guild invite, access control, and session reset.docs/index.md— Nav entry added under Deployment.package.json— Addeddiscord.js ^14.16.3dependency.Features
dc-ch-<channelId>)NEMOCLAW_MODELandSANDBOX_NAMEenv var support (consistent with Telegram bridge)ALLOWED_GUILD_IDSfor server-level access control!resetcommand to clear a channel's conversation sessionTesting
Closes #422.
Summary by CodeRabbit
New Features
Documentation
Chores