@nordbyte/nordrelay 0.6.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +52 -0
- package/README.md +171 -50
- package/dist/access-control.js +6 -1
- package/dist/activity-events.js +2 -2
- package/dist/adapter-conformance.js +61 -0
- package/dist/bot-preferences.js +1 -0
- package/dist/bot.js +95 -37
- package/dist/channel-adapter.js +44 -11
- package/dist/channel-command-catalog.js +94 -0
- package/dist/channel-command-core.js +60 -0
- package/dist/channel-command-service.js +230 -1
- package/dist/channel-mirror-registry.js +84 -0
- package/dist/channel-peer-prompt.js +95 -0
- package/dist/channel-prompt-engine.js +177 -0
- package/dist/channel-runtime.js +12 -5
- package/dist/channel-turn-lifecycle.js +73 -0
- package/dist/codex-state.js +114 -78
- package/dist/config-metadata.js +82 -8
- package/dist/config.js +79 -7
- package/dist/context-key.js +42 -0
- package/dist/discord-bot.js +173 -342
- package/dist/discord-command-surface.js +11 -73
- package/dist/index.js +29 -0
- package/dist/metrics.js +48 -0
- package/dist/peer-auth.js +85 -0
- package/dist/peer-client.js +288 -0
- package/dist/peer-context.js +21 -0
- package/dist/peer-identity.js +127 -0
- package/dist/peer-readiness.js +77 -0
- package/dist/peer-runtime-service.js +658 -0
- package/dist/peer-server.js +220 -0
- package/dist/peer-store.js +307 -0
- package/dist/peer-types.js +52 -0
- package/dist/relay-runtime-helpers.js +210 -0
- package/dist/relay-runtime.js +79 -274
- package/dist/remote-prompt.js +98 -0
- package/dist/settings-wizard-test.js +216 -0
- package/dist/slack-artifacts.js +165 -0
- package/dist/slack-bot.js +1461 -0
- package/dist/slack-channel-runtime.js +147 -0
- package/dist/slack-command-surface.js +46 -0
- package/dist/slack-diagnostics.js +116 -0
- package/dist/slack-rate-limit.js +139 -0
- package/dist/telegram-command-menu.js +3 -53
- package/dist/telegram-general-commands.js +14 -0
- package/dist/telegram-preference-commands.js +23 -127
- package/dist/user-management-crypto.js +38 -0
- package/dist/user-management-normalize.js +188 -0
- package/dist/user-management-types.js +1 -0
- package/dist/user-management.js +193 -196
- package/dist/web-api-contract.js +16 -0
- package/dist/web-dashboard-access-routes.js +62 -0
- package/dist/web-dashboard-assets.js +1 -0
- package/dist/web-dashboard-pages.js +26 -4
- package/dist/web-dashboard-peer-routes.js +225 -0
- package/dist/web-dashboard-ui.js +1 -0
- package/dist/web-dashboard.js +46 -0
- package/dist/web-state.js +2 -2
- package/dist/webui-assets/dashboard.css +193 -0
- package/dist/webui-assets/dashboard.js +870 -57
- package/package.json +5 -2
- package/plugins/nordrelay/scripts/nordrelay.mjs +468 -11
package/.env.example
CHANGED
|
@@ -56,6 +56,41 @@ DISCORD_QUIET_HOURS=
|
|
|
56
56
|
# Optional Discord override for automatic artifact summaries/uploads.
|
|
57
57
|
DISCORD_AUTO_SEND_ARTIFACTS=
|
|
58
58
|
|
|
59
|
+
# Slack
|
|
60
|
+
# Slack bot settings. Slack is opt-in and uses the same NordRelay users, groups, and permissions as Telegram and Discord.
|
|
61
|
+
# Start the Slack bot adapter.
|
|
62
|
+
SLACK_ENABLED=false
|
|
63
|
+
# Slack bot token.
|
|
64
|
+
SLACK_BOT_TOKEN=
|
|
65
|
+
# Slack app-level token for Socket Mode.
|
|
66
|
+
SLACK_APP_TOKEN=
|
|
67
|
+
# Slack signing secret for HTTP Events mode.
|
|
68
|
+
SLACK_SIGNING_SECRET=
|
|
69
|
+
# Use Slack Socket Mode instead of an HTTP events receiver.
|
|
70
|
+
SLACK_SOCKET_MODE=true
|
|
71
|
+
# HTTP port used when Slack Socket Mode is disabled.
|
|
72
|
+
SLACK_PORT=3000
|
|
73
|
+
# Optional comma-separated Slack team/workspace allow-list.
|
|
74
|
+
SLACK_ALLOWED_TEAM_IDS=
|
|
75
|
+
# Optional comma-separated Slack channel allow-list before user/group checks.
|
|
76
|
+
SLACK_ALLOWED_CHANNEL_IDS=
|
|
77
|
+
# Read regular Slack text messages as prompts.
|
|
78
|
+
SLACK_MESSAGE_CONTENT_ENABLED=true
|
|
79
|
+
# Slash command configured in Slack.
|
|
80
|
+
SLACK_COMMAND=/nordrelay
|
|
81
|
+
# Optional Slack override for CLI mirror mode. Uses the NordRelay default when unset.
|
|
82
|
+
# Options: off, status, final, full
|
|
83
|
+
SLACK_CLI_MIRROR_MODE=
|
|
84
|
+
# Optional Slack override for mirrored edit interval.
|
|
85
|
+
SLACK_CLI_MIRROR_MIN_UPDATE_MS=
|
|
86
|
+
# Optional Slack override for completion notifications.
|
|
87
|
+
# Options: off, minimal, all
|
|
88
|
+
SLACK_NOTIFY_MODE=
|
|
89
|
+
# Optional Slack quiet hours override. Use HH-HH, off, or leave blank for default.
|
|
90
|
+
SLACK_QUIET_HOURS=
|
|
91
|
+
# Optional Slack override for automatic artifact summaries/uploads.
|
|
92
|
+
SLACK_AUTO_SEND_ARTIFACTS=
|
|
93
|
+
|
|
59
94
|
# Agents
|
|
60
95
|
# Agent access. Codex is enabled by default; Pi, Hermes, OpenClaw, and Claude Code are opt-in.
|
|
61
96
|
# Allow Codex sessions.
|
|
@@ -264,6 +299,23 @@ NORDRELAY_VERSION_CACHE_TTL_MS=3600000
|
|
|
264
299
|
# Installed agent CLI version cache TTL.
|
|
265
300
|
NORDRELAY_CLI_VERSION_CACHE_TTL_MS=60000
|
|
266
301
|
|
|
302
|
+
# Peers
|
|
303
|
+
# Optional NordRelay-to-NordRelay federation. Pairing is explicit, authenticated, scoped, and TLS-protected.
|
|
304
|
+
# Expose the dedicated authenticated NordRelay peer API.
|
|
305
|
+
NORDRELAY_PEER_ENABLED=false
|
|
306
|
+
# Human-readable name shown to paired NordRelay instances.
|
|
307
|
+
NORDRELAY_PEER_NAME=
|
|
308
|
+
# Bind host for the peer API. Use 127.0.0.1 for local-only or a LAN/interface IP when explicitly exposing peers.
|
|
309
|
+
NORDRELAY_PEER_HOST=127.0.0.1
|
|
310
|
+
# Port for the peer API.
|
|
311
|
+
NORDRELAY_PEER_PORT=31979
|
|
312
|
+
# Optional public URL other instances should use for this node.
|
|
313
|
+
NORDRELAY_PEER_PUBLIC_URL=
|
|
314
|
+
# Serve the peer API over HTTPS with an automatically generated local certificate.
|
|
315
|
+
NORDRELAY_PEER_TLS_ENABLED=true
|
|
316
|
+
# Reject plaintext peer serving on non-loopback hosts.
|
|
317
|
+
NORDRELAY_PEER_REQUIRE_TLS=true
|
|
318
|
+
|
|
267
319
|
# Voice
|
|
268
320
|
# Optional voice transcription settings.
|
|
269
321
|
# Whisper fallback API key.
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# NordRelay
|
|
2
2
|
|
|
3
|
-
NordRelay is a remote control plane for coding agents across messaging channels. The current implementation connects Codex, Pi, Hermes, OpenClaw, and Claude Code coding-agent sessions to Telegram and
|
|
3
|
+
NordRelay is a remote control plane for coding agents across messaging channels and paired NordRelay instances. The current implementation connects Codex, Pi, Hermes, OpenClaw, and Claude Code coding-agent sessions to Telegram, Discord, Slack, the WebUI, and trusted peer nodes, keeps independent sessions per chat, thread, forum topic, DM, or remote target, streams replies and tool activity back to the active channel, supports files, photos, voice input, model controls, session browsing, retry/abort, CLI handback, and scoped multi-host control.
|
|
4
4
|
|
|
5
5
|
The repo is both a local Codex marketplace and a standalone Node app. The plugin lives in `plugins/nordrelay/`; the full bot runtime lives in `src/` and uses `@openai/codex-sdk` for Codex, Pi RPC mode for Pi, the Hermes API Server for Hermes, the OpenClaw Gateway WebSocket RPC surface for OpenClaw, and the Claude Agent SDK for Claude Code.
|
|
6
6
|
|
|
@@ -8,48 +8,62 @@ The repo is both a local Codex marketplace and a standalone Node app. The plugin
|
|
|
8
8
|
|
|
9
9
|
Session control:
|
|
10
10
|
|
|
11
|
-
- Independent coding-agent sessions per Telegram private chat, group chat, and
|
|
12
|
-
- `/agent` switches a
|
|
13
|
-
- Persistent
|
|
11
|
+
- Independent coding-agent sessions per Telegram private chat, group chat, forum topic, Discord DM/channel/thread, Slack DM/channel/thread, WebUI, and peer target.
|
|
12
|
+
- `/agent` switches a chat context between enabled agents such as Codex, Pi, Hermes, OpenClaw, and Claude Code.
|
|
13
|
+
- Persistent channel context metadata in the active workspace under `.nordrelay/contexts.json`.
|
|
14
14
|
- `/new` starts a fresh thread, with workspace selection when known workspaces are available.
|
|
15
15
|
- `/session` shows thread id, workspace, launch profile, launch behavior, model, reasoning, fast mode, context usage, token totals, and subscription limit remaining percentages.
|
|
16
16
|
- `/sessions` opens a paginated browser for recent sessions from the selected agent.
|
|
17
17
|
- `/sessions <query>` filters recent sessions by id, title, workspace, model, or first message.
|
|
18
|
-
- `/sync` manually refreshes the active
|
|
18
|
+
- `/sync` manually refreshes the active chat session from local CLI state when the selected agent supports state watching.
|
|
19
19
|
- `/pin`, `/unpin`, and `/pinned` keep important threads at the top of Telegram session browsing.
|
|
20
20
|
- `/switch <session-id>` switches directly to an existing session.
|
|
21
21
|
- `/attach <session-id>` binds an existing agent session to the current chat or topic.
|
|
22
22
|
- Existing thread metadata is imported on switch/attach, including model, reasoning effort, sandbox mode, and approval policy.
|
|
23
23
|
- Codex session usage is read from local rollout JSONL files, including context-used percent, total input/output tokens, 5h limit remaining, and weekly limit remaining.
|
|
24
24
|
- `/handback` returns a ready-to-run CLI command for continuing in the native agent CLI.
|
|
25
|
-
- `/retry` resends the last prompt for the current
|
|
26
|
-
- `/queue`, inline run/top/up/down/cancel buttons, `/cancel <queue-id>`, and `/clearqueue` manage queued prompts for a busy
|
|
25
|
+
- `/retry` resends the last prompt for the current chat context.
|
|
26
|
+
- `/queue`, inline run/top/up/down/cancel buttons, `/cancel <queue-id>`, and `/clearqueue` manage queued prompts for a busy chat context.
|
|
27
27
|
- `/queue later <minutes> <prompt>` schedules a prompt for later execution, and `/queue inspect <queue-id>` shows full queue metadata.
|
|
28
28
|
- `/abort`, `/stop`, and the inline Abort button cancel the active agent turn.
|
|
29
|
-
- Busy prompts are queued per
|
|
30
|
-
- If the attached thread is currently active in the local agent CLI,
|
|
31
|
-
- Active Codex, Pi, Hermes, OpenClaw, and Claude Code CLI/API turns are mirrored into Telegram with configurable `off`, `status`, `final`, or `full` modes.
|
|
32
|
-
- `/mirror` controls CLI mirroring per
|
|
29
|
+
- Busy prompts are queued per chat context instead of being dropped.
|
|
30
|
+
- If the attached thread is currently active in the local agent CLI, chat prompts are queued until that CLI task finishes.
|
|
31
|
+
- Active Codex, Pi, Hermes, OpenClaw, and Claude Code CLI/API turns are mirrored into Telegram, Discord, and Slack with configurable `off`, `status`, `final`, or `full` modes.
|
|
32
|
+
- `/mirror` controls CLI mirroring per chat context.
|
|
33
33
|
- Queues survive connector restarts and are resumed automatically when the external CLI turn becomes idle.
|
|
34
|
-
- `/notify` controls completion/status notifications and quiet hours per
|
|
34
|
+
- `/notify` controls completion/status notifications and quiet hours per chat context.
|
|
35
35
|
- `/workspaces` lists allowed workspaces and shows workspace guardrail warnings.
|
|
36
|
-
- `/status`, `/health`, and `/version` report connector runtime health from
|
|
36
|
+
- `/status`, `/health`, and `/version` report connector runtime health from chat adapters.
|
|
37
37
|
- `/tasks` and `/progress` show the current turn status, queue length, active tool, elapsed time, and last error.
|
|
38
38
|
- `/activity` shows a compact timeline of recent rollout events for the active thread, with filters and export.
|
|
39
|
-
- `/diagnostics` reports redacted runtime, config, user/group authorization,
|
|
39
|
+
- `/diagnostics` reports redacted runtime, config, user/group authorization, channel rate-limit, mirror, voice, session, queue, and progress details.
|
|
40
40
|
- `/support` exports a redacted diagnostics ZIP with config, health, versions, agent paths, recent logs, audit events, update jobs, state backend, and OS/Node/npm info.
|
|
41
41
|
- `/lock`, `/unlock`, and `/locks` provide a team write-lock for shared sessions so one user can operate while others watch.
|
|
42
|
-
- `/audit` shows recent prompt, queue, lock, command, authentication, permission-denied, user, group, Telegram-link, Telegram-chat, and web-session audit events for admins.
|
|
42
|
+
- `/audit` shows recent prompt, queue, lock, command, authentication, permission-denied, user, group, Telegram-link, Telegram-chat, Discord-link, Discord-channel, Slack-link, Slack-channel, and web-session audit events for admins.
|
|
43
43
|
|
|
44
44
|
Adapter architecture:
|
|
45
45
|
|
|
46
46
|
- Telegram supports text, typing, streaming edits, inline buttons, files, photos, voice, forum topics, and polling/webhook transport.
|
|
47
47
|
- Discord supports text, typing, streaming edits, buttons, files, photos, voice/audio transcription, guild channels, threads, DMs, message commands, and slash commands.
|
|
48
|
-
-
|
|
48
|
+
- Slack supports text, typing/status, streaming edits, Block Kit buttons, files, images, audio transcription, channels, DMs, threads, Socket Mode, and HTTP Events mode.
|
|
49
|
+
- Slack startup and `/diagnostics` include readiness checks for token/transport configuration, registered channels, Slack API auth probes, channel visibility probes, file-upload readiness notes, and rate-limit counters.
|
|
50
|
+
- `/channels` shows available and planned messaging adapters for Telegram, Discord, Slack, WhatsApp, and Matrix.
|
|
49
51
|
- Codex, Pi, Hermes, OpenClaw, and Claude Code are implemented as agent adapters.
|
|
50
52
|
- `/agents` shows available/planned agent adapters and whether Codex, Pi, Hermes, OpenClaw, and Claude Code are enabled.
|
|
53
|
+
- Agent and chat adapters expose a shared conformance matrix so command coverage and feature support can be tested and surfaced consistently.
|
|
51
54
|
- Shared command-action renderers and a channel runtime contract keep inbound commands, outbound messages, typing, files, inline actions, and streaming-ready delivery separate from channel-specific API calls.
|
|
52
55
|
|
|
56
|
+
Peer federation:
|
|
57
|
+
|
|
58
|
+
- Optional NordRelay-to-NordRelay pairing lets one instance operate agents on trusted Ubuntu, macOS, Windows, LAN, or remote hosts.
|
|
59
|
+
- Peer serving is disabled by default and uses a dedicated API port separate from the dashboard.
|
|
60
|
+
- Pairing requires an explicit one-time invitation code, Ed25519 node identity verification, a per-peer shared secret, request HMAC signatures, timestamp/nonce replay protection, and TLS fingerprint pinning.
|
|
61
|
+
- Peer scopes restrict which remote WebUI/API actions are allowed, including read, prompt, queue, file, diagnostic, log, and session permissions.
|
|
62
|
+
- Peer records can also restrict allowed agent ids, allowed workspace roots, and per-peer workspace aliases such as `app=/srv/app`.
|
|
63
|
+
- The WebUI has a Peers page plus a local/remote target selector; dashboard pages, SSE streaming, queue actions, artifact downloads, health checks, and the global session browser proxy through the selected peer when allowed.
|
|
64
|
+
- Telegram, Discord, and Slack expose `/peers` and `/target` so a linked user can choose whether prompts run locally or on a paired NordRelay instance.
|
|
65
|
+
- Remote prompts stream text, tool status, turn completion, and errors back to the originating Telegram, Discord, or Slack context.
|
|
66
|
+
|
|
53
67
|
Codex runtime:
|
|
54
68
|
|
|
55
69
|
- Uses `@openai/codex-sdk` to start, resume, and stream Codex threads.
|
|
@@ -59,18 +73,18 @@ Codex runtime:
|
|
|
59
73
|
- Supports launch profiles through `/launch_profiles` and `/launch`.
|
|
60
74
|
- Built-in launch profiles include Default, Read Only, Review, and optional Full Access.
|
|
61
75
|
- Custom launch profiles can be configured with `CODEX_LAUNCH_PROFILES_JSON`.
|
|
62
|
-
- Unsafe `danger-full-access` profiles require `ENABLE_UNSAFE_LAUNCH_PROFILES=true` and
|
|
63
|
-
- Review or unsafe launch profiles require an inline
|
|
76
|
+
- Unsafe `danger-full-access` profiles require `ENABLE_UNSAFE_LAUNCH_PROFILES=true` and channel confirmation.
|
|
77
|
+
- Review or unsafe launch profiles require an inline channel approval before each prompt is executed.
|
|
64
78
|
- Fast mode can be toggled with `/fast` and mirrors Codex's `fast_default_opt_out` setting from `~/.codex/config.toml`.
|
|
65
|
-
- Active
|
|
66
|
-
- Active local Codex CLI tasks are detected from rollout JSONL files so
|
|
79
|
+
- Active chat sessions periodically sync model, reasoning, workspace, launch metadata, and fast-mode defaults from local agent state where supported.
|
|
80
|
+
- Active local Codex CLI tasks are detected from rollout JSONL files so chat adapters do not race the CLI on the same thread.
|
|
67
81
|
- `/diagnostics` includes rollout path, activity status, stale/idle reason, line count, and last update time.
|
|
68
82
|
- Optional per-turn token usage footer with `SHOW_TURN_TOKEN_USAGE=true`.
|
|
69
83
|
|
|
70
84
|
Pi runtime:
|
|
71
85
|
|
|
72
86
|
- Pi support is opt-in with `NORDRELAY_PI_ENABLED=true`.
|
|
73
|
-
- The default
|
|
87
|
+
- The default chat agent is selected with `NORDRELAY_DEFAULT_AGENT=codex`, `pi`, `hermes`, `openclaw`, or `claude-code`.
|
|
74
88
|
- Pi sessions are driven through official `pi --mode rpc` JSONL commands and events.
|
|
75
89
|
- Existing Pi sessions are discovered from `~/.pi/agent/sessions/` or `PI_SESSION_DIR`.
|
|
76
90
|
- `/sessions`, `/switch`, `/attach`, `/new`, `/session`, `/handback`, `/model`, `/reasoning`, `/abort`, `/stop`, `/retry`, `/queue`, files, photos, and voice input work for Pi contexts.
|
|
@@ -78,15 +92,15 @@ Pi runtime:
|
|
|
78
92
|
- Pi thinking levels use `/reasoning` and support `off`, `minimal`, `low`, `medium`, `high`, and `xhigh`.
|
|
79
93
|
- Pi token and context stats are read through `get_session_stats` when an RPC session is active.
|
|
80
94
|
- Pi launch profiles expose CLI safety modes such as default, read-only tools, no tools, offline, and safe offline.
|
|
81
|
-
- Pi external CLI activity is detected from Pi session JSONL files so
|
|
82
|
-
- Pi CLI turns can be mirrored into
|
|
95
|
+
- Pi external CLI activity is detected from Pi session JSONL files so chat/WebUI prompts queue while the same Pi session is busy.
|
|
96
|
+
- Pi CLI turns can be mirrored into chat adapters and the WebUI with status, tool activity, final answers, activity timelines, diagnostics, and generated artifact discovery.
|
|
83
97
|
- Pi provider auth checks report the environment variables expected for the selected provider.
|
|
84
98
|
- Codex-only subscription limit percentages remain Codex-specific; Pi reports token/context stats when available.
|
|
85
99
|
|
|
86
100
|
Hermes runtime:
|
|
87
101
|
|
|
88
102
|
- Hermes support is opt-in with `NORDRELAY_HERMES_ENABLED=true`.
|
|
89
|
-
- The default
|
|
103
|
+
- The default chat agent can be set with `NORDRELAY_DEFAULT_AGENT=hermes`.
|
|
90
104
|
- Hermes turns are executed through the Hermes API Server `/v1/runs` endpoint and streamed through `/v1/runs/{run_id}/events`.
|
|
91
105
|
- `/abort` and `/stop` use the Hermes run stop endpoint when a NordRelay-started Hermes run is active.
|
|
92
106
|
- Existing Hermes sessions are discovered from `~/.hermes/state.db`, or from `HERMES_STATE_DB_PATH` when configured.
|
|
@@ -94,14 +108,14 @@ Hermes runtime:
|
|
|
94
108
|
- Hermes model selection uses `/v1/models` when the API Server is reachable and falls back to the selected/default model.
|
|
95
109
|
- Hermes reasoning uses `/reasoning` and supports `none`, `minimal`, `low`, `medium`, `high`, and `xhigh`.
|
|
96
110
|
- Hermes launch profiles include `default`, `safe`, `readonly`, and `yolo`; profiles map to run instructions and Hermes approval responses.
|
|
97
|
-
- Hermes external activity is detected from `state.db`, so
|
|
98
|
-
- Hermes CLI/API turns can be mirrored into
|
|
111
|
+
- Hermes external activity is detected from `state.db`, so chat/WebUI prompts queue while the same Hermes session has an unfinished CLI turn.
|
|
112
|
+
- Hermes CLI/API turns can be mirrored into chat adapters and the WebUI with status, tool activity, final answers, activity timelines, diagnostics, and generated artifact discovery.
|
|
99
113
|
- `/auth` checks that the Hermes API Server is reachable and that `HERMES_API_KEY` is usable when configured.
|
|
100
114
|
|
|
101
115
|
OpenClaw runtime:
|
|
102
116
|
|
|
103
117
|
- OpenClaw support is opt-in with `NORDRELAY_OPENCLAW_ENABLED=true`.
|
|
104
|
-
- The default
|
|
118
|
+
- The default chat agent can be set with `NORDRELAY_DEFAULT_AGENT=openclaw`.
|
|
105
119
|
- OpenClaw turns are executed through the OpenClaw Gateway WebSocket RPC endpoint configured by `OPENCLAW_GATEWAY_URL`.
|
|
106
120
|
- `/abort` and `/stop` call the OpenClaw Gateway cancel method when a NordRelay-started OpenClaw run is active.
|
|
107
121
|
- Existing OpenClaw sessions are discovered from `openclaw sessions --all-agents --json`, or from the state directory configured with `OPENCLAW_HOME` or `OPENCLAW_STATE_DIR`.
|
|
@@ -109,22 +123,22 @@ OpenClaw runtime:
|
|
|
109
123
|
- OpenClaw model selection uses the Gateway `models.list` method when reachable and falls back to `openclaw models list --json`.
|
|
110
124
|
- OpenClaw thinking uses `/reasoning` and supports `off`, `minimal`, `low`, `medium`, `high`, and `xhigh`.
|
|
111
125
|
- OpenClaw launch profiles include `default`, `safe`, `readonly`, `local`, and `deliver`; profiles map to Gateway run flags and additional instructions.
|
|
112
|
-
- OpenClaw external activity is detected from OpenClaw session state, so
|
|
113
|
-
- OpenClaw Gateway turns can be mirrored into
|
|
126
|
+
- OpenClaw external activity is detected from OpenClaw session state, so chat/WebUI prompts queue while the same OpenClaw session has an unfinished CLI turn.
|
|
127
|
+
- OpenClaw Gateway turns can be mirrored into chat adapters and the WebUI with status, tool activity, final answers, activity timelines, diagnostics, and generated artifact discovery.
|
|
114
128
|
- `/auth` checks that the OpenClaw Gateway is reachable and that `OPENCLAW_GATEWAY_TOKEN` or `OPENCLAW_GATEWAY_PASSWORD` is usable when configured.
|
|
115
129
|
|
|
116
130
|
Claude Code runtime:
|
|
117
131
|
|
|
118
132
|
- Claude Code support is opt-in with `NORDRELAY_CLAUDE_CODE_ENABLED=true`.
|
|
119
|
-
- The default
|
|
133
|
+
- The default chat agent can be set with `NORDRELAY_DEFAULT_AGENT=claude-code`.
|
|
120
134
|
- Claude Code turns are executed through `@anthropic-ai/claude-agent-sdk`, using the host `claude` executable when available and the SDK bundled runtime otherwise.
|
|
121
135
|
- Existing Claude Code sessions are discovered from `~/.claude/projects/`, or from `CLAUDE_CONFIG_DIR/projects` when configured.
|
|
122
136
|
- `/sessions`, `/switch`, `/attach`, `/new`, `/session`, `/handback`, `/model`, `/reasoning`, `/abort`, `/stop`, `/retry`, `/queue`, files, photos, and voice input work for Claude Code contexts.
|
|
123
137
|
- Claude Code model selection exposes common aliases and model ids; explicit values from existing sessions are preserved.
|
|
124
138
|
- Claude Code effort uses `/reasoning` and supports `off`, `low`, `medium`, `high`, and `xhigh`.
|
|
125
139
|
- Claude Code launch profiles include `default`, `accept-edits`, `plan`, `readonly`, `no-tools`, and optional `bypass-permissions`.
|
|
126
|
-
- Claude Code external activity is detected from transcript JSONL files, so
|
|
127
|
-
- Claude Code SDK turns can be mirrored into
|
|
140
|
+
- Claude Code external activity is detected from transcript JSONL files, so chat/WebUI prompts queue while the same Claude Code session has an unfinished CLI turn.
|
|
141
|
+
- Claude Code SDK turns can be mirrored into chat adapters and the WebUI with status, tool activity, final answers, activity timelines, diagnostics, and generated artifact discovery.
|
|
128
142
|
- `/auth` checks the host Claude Code CLI auth state when `claude auth status` is available.
|
|
129
143
|
|
|
130
144
|
Telegram input:
|
|
@@ -162,7 +176,7 @@ Telegram output:
|
|
|
162
176
|
|
|
163
177
|
Discord input and output:
|
|
164
178
|
|
|
165
|
-
- Enable Discord with `DISCORD_ENABLED=true` and `DISCORD_BOT_TOKEN`.
|
|
179
|
+
- Enable Discord with `DISCORD_ENABLED=true` and `DISCORD_BOT_TOKEN`. If a requested chat adapter is missing its token, NordRelay disables that adapter and keeps running as long as another chat adapter is usable.
|
|
166
180
|
- Set `DISCORD_CLIENT_ID` to let NordRelay register slash commands automatically.
|
|
167
181
|
- `DISCORD_COMMAND_MODE=both` supports slash commands and `/command` text messages. Set it to `slash` if the bot should not read message commands.
|
|
168
182
|
- `DISCORD_MESSAGE_CONTENT_ENABLED=true` lets regular Discord messages become prompts. The matching privileged intent must also be enabled in the Discord Developer Portal.
|
|
@@ -171,22 +185,33 @@ Discord input and output:
|
|
|
171
185
|
- Discord buttons cover session picks, model/reasoning/launch picks, queue actions, artifact actions, update jobs, and abort where Discord component limits allow.
|
|
172
186
|
- Discord slash commands mirror the Telegram command surface where Discord supports it: `/agent`, `/auth`, `/login`, `/logout`, `/session`, `/sessions`, `/new`, `/switch`, `/attach`, `/handback`, `/workspaces`, `/pin`, `/unpin`, `/pinned`, `/model`, `/reasoning`, `/fast`, `/launch`, `/launch_profiles`, `/queue`, `/stop`, `/retry`, `/sync`, `/progress`, `/activity`, `/audit`, `/artifacts`, `/logs`, `/version`, `/diagnostics`, `/restart`, `/update`, `/lock`, `/unlock`, `/mirror`, `/notify`, `/voice`, `/link`, `/whoami`, and `/register_channel`.
|
|
173
187
|
|
|
188
|
+
Slack input and output:
|
|
189
|
+
|
|
190
|
+
- Enable Slack with `SLACK_ENABLED=true`, `SLACK_BOT_TOKEN`, and `SLACK_APP_TOKEN` for Socket Mode. If Socket Mode is disabled, set `SLACK_SIGNING_SECRET` and expose the Slack HTTP receiver.
|
|
191
|
+
- `SLACK_MESSAGE_CONTENT_ENABLED=true` lets regular Slack messages become prompts. Keep it disabled if you only want slash-command control.
|
|
192
|
+
- Slack DMs, channels, and message threads get independent NordRelay contexts.
|
|
193
|
+
- Slack files are staged like Telegram/Discord uploads; images are passed as image inputs and audio files are transcribed before prompting.
|
|
194
|
+
- Slack Block Kit buttons cover session picks, model/reasoning/launch picks, queue actions, artifact actions, update jobs, and abort where Slack component limits allow.
|
|
195
|
+
- Slack slash/text commands mirror the shared command surface where Slack supports it: `/agent`, `/auth`, `/login`, `/logout`, `/session`, `/sessions`, `/new`, `/switch`, `/attach`, `/handback`, `/workspaces`, `/pin`, `/unpin`, `/pinned`, `/model`, `/reasoning`, `/fast`, `/launch`, `/launch_profiles`, `/queue`, `/stop`, `/retry`, `/sync`, `/progress`, `/activity`, `/audit`, `/artifacts`, `/logs`, `/version`, `/diagnostics`, `/restart`, `/update`, `/lock`, `/unlock`, `/mirror`, `/notify`, `/voice`, `/link`, `/whoami`, and `/register_channel`.
|
|
196
|
+
|
|
174
197
|
Authentication and safety:
|
|
175
198
|
|
|
176
199
|
- WebUI login is required for every dashboard page, API route, SSE stream, artifact download, and health endpoint.
|
|
177
|
-
- Access is managed through NordRelay users, groups, permissions, web sessions, linked Telegram identities, and linked
|
|
178
|
-
- Built-in groups are `Admin`, `User`, and `Read Only`; custom groups can be created in the WebUI and can restrict allowed agents, workspace roots, Telegram chats, and
|
|
200
|
+
- Access is managed through NordRelay users, groups, permissions, web sessions, linked Telegram identities, linked Discord identities, and linked Slack identities.
|
|
201
|
+
- Built-in groups are `Admin`, `User`, and `Read Only`; custom groups can be created in the WebUI and can restrict allowed agents, workspace roots, Telegram chats, Discord channels, and Slack channels.
|
|
179
202
|
- The last active admin cannot be disabled or demoted, and web sessions are revoked when passwords or group memberships change.
|
|
180
203
|
- Admins can review and revoke active WebUI sessions from the Users page.
|
|
181
204
|
- Telegram private chats require a linked active NordRelay user.
|
|
182
205
|
- Telegram group and forum chats must be registered before use; admins can run `/register_chat` in the chat or enable chats in the WebUI.
|
|
183
206
|
- Discord DMs require a linked active NordRelay user.
|
|
184
207
|
- Discord guild channels and threads must be registered before use; admins can run `/register_channel` in the channel or enable channels in the WebUI.
|
|
208
|
+
- Slack DMs require a linked active NordRelay user.
|
|
209
|
+
- Slack channels and threads must be registered before use; admins can run `/register_channel` in the channel or enable channels in the WebUI.
|
|
185
210
|
- `/whoami` shows the linked NordRelay account and groups.
|
|
186
211
|
- `/link <code>` links a Telegram account to a NordRelay user after a link code is created in the WebUI or with `nordrelay user link-code`.
|
|
187
|
-
- `/link <code>` also links a Discord account when the code was created
|
|
212
|
+
- `/link <code>` also links a Discord or Slack account when the code was created for that channel.
|
|
188
213
|
- WebUI login and chat-account link attempts are rate-limited to reduce brute-force risk.
|
|
189
|
-
- User, group, Telegram-link, Telegram-chat, Discord-link, Discord-channel, web-session, login, and permission-denied events are written to the audit log.
|
|
214
|
+
- User, group, Telegram-link, Telegram-chat, Discord-link, Discord-channel, Slack-link, Slack-channel, web-session, login, and permission-denied events are written to the audit log.
|
|
190
215
|
- `/auth` reports Codex authentication, Pi provider environment health, Hermes API Server reachability, OpenClaw Gateway reachability, or Claude Code CLI auth for the selected agent.
|
|
191
216
|
- `/login` starts Telegram-managed CLI auth for Codex, Hermes, or Claude Code when enabled.
|
|
192
217
|
- `/logout` signs out of CLI auth for Codex, Hermes, or Claude Code; Codex logout is disabled while `CODEX_API_KEY` is in use.
|
|
@@ -200,15 +225,16 @@ Operations:
|
|
|
200
225
|
- Plugin command/skill starts, stops, restarts, and inspects the connector process.
|
|
201
226
|
- Manual process commands support `start`, `stop`, `restart`, `status`, `update`, and `foreground`.
|
|
202
227
|
- Telegram admin commands support `/logs`, `/diagnostics`, `/support`, `/restart`, and `/update` for NordRelay and agent CLIs.
|
|
228
|
+
- `nordrelay peer identity`, `list`, `invite`, `add`, `test`, and `revoke` manage secure peer federation from the CLI.
|
|
203
229
|
- `nordrelay update`, `/update`, and the WebUI update button detect the install type: npm installs update with `npm install -g @nordbyte/nordrelay@latest`; source checkouts pull `origin/main`, install dependencies, run check, tests, and build, then restart if the connector is running.
|
|
204
230
|
- `/update agents`, `/update <agent>`, `/update install <agent>`, `/update jobs`, `/update log <id>`, `/update cancel <id>`, and `/update input <id> <text>` manage Codex, Pi, Hermes, OpenClaw, and Claude Code updater or installer jobs from Telegram.
|
|
205
231
|
- `/logs` renders redacted connector, NordRelay update, and agent update logs with local-time timestamps, levels, file path, last-modified time, and highlighted warnings/errors.
|
|
206
232
|
- Logs can be emitted as timestamped plain text or JSON records with `CONNECTOR_LOG_FORMAT`.
|
|
207
233
|
- Telegram sends/edits/documents are routed through a rate-limit queue that honors Telegram retry-after responses.
|
|
208
|
-
- Mirror, notification, quiet-hour, and automatic artifact-delivery defaults are configured through channel-neutral `NORDRELAY_*` settings, with Telegram and
|
|
234
|
+
- Mirror, notification, quiet-hour, and automatic artifact-delivery defaults are configured through channel-neutral `NORDRELAY_*` settings, with Telegram, Discord, and Slack override keys when a channel should differ.
|
|
209
235
|
- The WebUI Tasks page includes a unified Jobs view for active WebUI turns, external CLI turns, queued prompts, agent update/install jobs, self-updates, and diagnostics bundle exports, with log, cancel, and retry actions where supported.
|
|
210
236
|
- Unified Jobs are persisted across restarts and retain recent prompt, queue, update, connector-update, and support-bundle history for WebUI inspection.
|
|
211
|
-
- The WebUI Metrics page reports queue state, active/completed/failed turns, job counts, average prompt duration, and Telegram/Discord rate-limit counters.
|
|
237
|
+
- The WebUI Metrics page reports queue state, active/completed/failed turns, job counts, average prompt duration, and Telegram/Discord/Slack rate-limit counters.
|
|
212
238
|
- Expensive dashboard views such as version checks, adapter health, and diagnostics use a short stale-while-refresh server cache so the UI can render recent data while fresh checks run in the background.
|
|
213
239
|
- Context metadata, queues, and preferences are written atomically with backup recovery.
|
|
214
240
|
- Context metadata, queues, preferences, audit events, and locks can use JSON files or the optional SQLite state backend with `NORDRELAY_STATE_BACKEND=sqlite`.
|
|
@@ -217,7 +243,7 @@ Operations:
|
|
|
217
243
|
- On first WebUI startup without an admin account, NordRelay shows a setup wizard for creating the first admin; remote setup requires the one-time token printed in the server console.
|
|
218
244
|
- The WebUI has responsive header/sidebar/footer navigation, live chat streaming, session controls, queue/artifact/log/diagnostic views, and settings management.
|
|
219
245
|
- The WebUI supports light and dark themes, tabbed settings groups, paginated session browsing, and chat uploads for images, documents, and audio transcription.
|
|
220
|
-
- The WebUI exposes REST and SSE endpoints for chat streaming, sessions, settings, queue, artifacts, logs, health, diagnostics, and redacted diagnostics bundle export.
|
|
246
|
+
- The WebUI exposes REST and SSE endpoints for chat streaming, sessions, settings, queue, artifacts, logs, health, diagnostics, peers, adapter conformance, and redacted diagnostics bundle export.
|
|
221
247
|
- The dashboard can bind to `127.0.0.1` or `0.0.0.0`; user login and session cookies are mandatory in both modes.
|
|
222
248
|
- Telegram can run with long polling or an HTTP webhook via `TELEGRAM_TRANSPORT=webhook`.
|
|
223
249
|
- Version freshness checks are cached with `NORDRELAY_VERSION_CACHE_TTL_MS`, and installed agent CLI version checks are cached with `NORDRELAY_CLI_VERSION_CACHE_TTL_MS`, to keep `/version` and adapter health responsive.
|
|
@@ -289,6 +315,16 @@ Create the Discord bot:
|
|
|
289
315
|
6. Link Discord from the WebUI, with `nordrelay user link-discord`, or by creating a Discord link code and sending `/link <code>` to the bot.
|
|
290
316
|
7. In guild channels, run `/register_channel` once from an admin-linked Discord account.
|
|
291
317
|
|
|
318
|
+
Create the Slack app:
|
|
319
|
+
|
|
320
|
+
1. Open Slack API Apps and create a new app for your workspace.
|
|
321
|
+
2. Add a bot user and copy the bot token into `SLACK_BOT_TOKEN`.
|
|
322
|
+
3. Enable Socket Mode and create an app-level token with `connections:write`; copy it into `SLACK_APP_TOKEN`.
|
|
323
|
+
4. Add bot scopes for messages, files, channels, groups, IMs, MPIMs, commands, and chat write access.
|
|
324
|
+
5. Create the slash command configured in `SLACK_COMMAND` (default `/nordrelay`) and install the app to your workspace.
|
|
325
|
+
6. Link Slack from the WebUI, with `nordrelay user link-slack`, or by creating a Slack link code and sending `/link <code>` to the app.
|
|
326
|
+
7. In Slack channels, run `/register_channel` once from an admin-linked Slack account.
|
|
327
|
+
|
|
292
328
|
Minimal private-bot `~/.nordrelay/nordrelay.env`:
|
|
293
329
|
|
|
294
330
|
```dotenv
|
|
@@ -296,6 +332,9 @@ TELEGRAM_BOT_TOKEN=123456789:replace-me
|
|
|
296
332
|
DISCORD_ENABLED=false
|
|
297
333
|
DISCORD_BOT_TOKEN=
|
|
298
334
|
DISCORD_CLIENT_ID=
|
|
335
|
+
SLACK_ENABLED=false
|
|
336
|
+
SLACK_BOT_TOKEN=
|
|
337
|
+
SLACK_APP_TOKEN=
|
|
299
338
|
NORDRELAY_CODEX_ENABLED=true
|
|
300
339
|
NORDRELAY_PI_ENABLED=false
|
|
301
340
|
NORDRELAY_HERMES_ENABLED=false
|
|
@@ -313,10 +352,40 @@ User and chat access management:
|
|
|
313
352
|
- `nordrelay user create --email dev@example.com --name "Dev" --group user` creates a normal user.
|
|
314
353
|
- `nordrelay user link-telegram --email you@example.com --telegram-user-id 123456789` links a Telegram account directly.
|
|
315
354
|
- `nordrelay user link-discord --email you@example.com --discord-user-id 123456789012345678` links a Discord account directly.
|
|
355
|
+
- `nordrelay user link-slack --email you@example.com --slack-user-id U123 --slack-team-id T123` links a Slack account directly.
|
|
316
356
|
- `nordrelay user link-code --email you@example.com` creates a short-lived Telegram code that the user sends as `/link <code>` to the Telegram bot.
|
|
317
357
|
- `nordrelay user discord-link-code --email you@example.com` creates a short-lived Discord code that the user sends as `/link <code>` to the Discord bot.
|
|
358
|
+
- `nordrelay user slack-link-code --email you@example.com` creates a short-lived Slack code that the user sends as `/link <code>` to the Slack app.
|
|
318
359
|
- Telegram group chats are disabled until an admin enables them from the WebUI or runs `/register_chat` inside the group.
|
|
319
360
|
- Discord guild channels are disabled until an admin enables them from the WebUI or runs `/register_channel` inside the channel.
|
|
361
|
+
- Slack channels are disabled until an admin enables them from the WebUI or runs `/register_channel` inside the channel.
|
|
362
|
+
|
|
363
|
+
Peer setup:
|
|
364
|
+
|
|
365
|
+
1. On each host that should accept peer connections, set `NORDRELAY_PEER_ENABLED=true` in `~/.nordrelay/nordrelay.env`.
|
|
366
|
+
2. Keep `NORDRELAY_PEER_TLS_ENABLED=true` and `NORDRELAY_PEER_REQUIRE_TLS=true` for LAN or internet use.
|
|
367
|
+
3. Use `NORDRELAY_PEER_HOST=127.0.0.1` for local-only testing, a LAN/interface IP for trusted local networks, or keep the peer API behind a TLS reverse proxy/VPN for internet access.
|
|
368
|
+
4. Set `NORDRELAY_PEER_PUBLIC_URL=https://host.example:31979` when other hosts cannot reach the bind address directly.
|
|
369
|
+
5. Restart NordRelay on the accepting host and create an invitation:
|
|
370
|
+
|
|
371
|
+
```bash
|
|
372
|
+
nordrelay peer invite --name workstation --scopes inspect,sessions.read,sessions.write,prompt.send,prompt.abort,queue.read,queue.write,files.read,files.write,diagnostics.read,logs.read
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
6. On the controlling host, run the printed command:
|
|
376
|
+
|
|
377
|
+
```bash
|
|
378
|
+
nordrelay peer add https://workstation.example:31979 --code one-time-code
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
7. Confirm the connection:
|
|
382
|
+
|
|
383
|
+
```bash
|
|
384
|
+
nordrelay peer list
|
|
385
|
+
nordrelay peer test <peer-id>
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
Use `--workspace-aliases app=/srv/app,demo=/home/me/demo` on invites when a controller should be able to start remote sessions with short workspace names. Use the WebUI Peers page for the same invite, pair, enable/disable, test, alias, global-session, and revoke workflow. Use `/peers` from Telegram, Discord, or Slack to inspect paired nodes and `/target <peer-id>` or `/target local` to choose where subsequent prompts run.
|
|
320
389
|
|
|
321
390
|
Codex authentication:
|
|
322
391
|
|
|
@@ -403,6 +472,9 @@ nordrelay restart
|
|
|
403
472
|
nordrelay stop
|
|
404
473
|
nordrelay foreground
|
|
405
474
|
nordrelay web
|
|
475
|
+
nordrelay peer list
|
|
476
|
+
nordrelay peer invite
|
|
477
|
+
nordrelay peer add https://peer.example:31979 --code one-time-code
|
|
406
478
|
```
|
|
407
479
|
|
|
408
480
|
Source checkout process commands:
|
|
@@ -417,6 +489,7 @@ node plugins/nordrelay/scripts/nordrelay.mjs foreground
|
|
|
417
489
|
node plugins/nordrelay/scripts/nordrelay.mjs user list
|
|
418
490
|
node plugins/nordrelay/scripts/nordrelay.mjs doctor
|
|
419
491
|
node plugins/nordrelay/scripts/nordrelay.mjs web
|
|
492
|
+
node plugins/nordrelay/scripts/nordrelay.mjs peer list
|
|
420
493
|
```
|
|
421
494
|
|
|
422
495
|
NPM shortcuts:
|
|
@@ -472,6 +545,7 @@ The dashboard is a second NordRelay client next to Telegram. It can:
|
|
|
472
545
|
- Inspect a per-agent capability matrix showing model, reasoning, launch, fast mode, attachments, activity, usage, auth, login/logout, and handback support.
|
|
473
546
|
- Check NordRelay and agent CLI versions, then start Codex, Pi, Hermes, OpenClaw, or Claude Code updates from outdated rows or installs from not-installed rows with live output, cancel, delete-log, and stdin response controls.
|
|
474
547
|
- Build dashboard CSS and client JavaScript from modular source assets through esbuild, then serve them as authenticated static assets instead of inline HTML.
|
|
548
|
+
- Pair, test, enable/disable, and revoke NordRelay peers, then switch the dashboard target between the local instance and paired remote instances.
|
|
475
549
|
|
|
476
550
|
Dashboard API endpoints are served under `/api/*`. Streaming uses `GET /api/events`.
|
|
477
551
|
|
|
@@ -504,6 +578,8 @@ Run NordRelay behind your reverse proxy so the public URL forwards to `http://12
|
|
|
504
578
|
- `/channels` shows available and planned messaging adapters.
|
|
505
579
|
- `/agents` shows available and planned coding-agent adapters.
|
|
506
580
|
- `/agent` selects the active agent for this Telegram context.
|
|
581
|
+
- `/peers` shows configured NordRelay peer instances.
|
|
582
|
+
- `/target local|<peer-id>` selects whether prompts for this chat run locally or on a paired peer.
|
|
507
583
|
- `/link <code>` links the Telegram account to a NordRelay user.
|
|
508
584
|
- `/whoami` shows the linked NordRelay user, groups, and permissions.
|
|
509
585
|
- `/register_chat` enables the current Telegram group or forum chat for NordRelay when the linked user has user-management permission.
|
|
@@ -575,10 +651,24 @@ Discord supports slash commands and `/command` text messages for the shared comm
|
|
|
575
651
|
- `/prompt <text>` is available for slash-command-only deployments where regular message content is disabled.
|
|
576
652
|
- `/link <code>` consumes Discord link codes created in the WebUI or with `nordrelay user discord-link-code`.
|
|
577
653
|
- `/queue`, `/sessions`, `/agent`, `/model`, `/reasoning`, `/launch`, `/artifacts`, `/update`, and `/stop` use Discord buttons where component limits allow.
|
|
654
|
+
- `/peers` and `/target local|<peer-id>` use the same paired-instance target selection as Telegram.
|
|
578
655
|
- `/artifacts latest`, `/artifacts zip latest`, `/artifacts images`, `/artifacts docs`, `/artifacts search <text>`, and `/artifacts delete <turn-id>` are available in Discord.
|
|
579
656
|
- Unsafe launch profiles require explicit confirmation with `/launch <profile-id> confirm`.
|
|
580
657
|
- Discord does not support Telegram reactions or Telegram webhook transport; typing, message edits, attachments, files, DMs, guild channels, and threads are supported.
|
|
581
658
|
|
|
659
|
+
## Slack Commands
|
|
660
|
+
|
|
661
|
+
Slack supports the configured slash command and `/command` text messages for the shared command set. The primary differences from Telegram are:
|
|
662
|
+
|
|
663
|
+
- `/register_channel` enables the current Slack channel or thread for NordRelay when the linked user has user-management permission.
|
|
664
|
+
- `/prompt <text>` is available through the configured slash command when regular message content is disabled.
|
|
665
|
+
- `/link <code>` consumes Slack link codes created in the WebUI or with `nordrelay user slack-link-code`.
|
|
666
|
+
- `/queue`, `/sessions`, `/agent`, `/model`, `/reasoning`, `/launch`, `/artifacts`, `/update`, and `/stop` use Slack buttons where Block Kit limits allow.
|
|
667
|
+
- `/peers` and `/target local|<peer-id>` use the same paired-instance target selection as Telegram and Discord.
|
|
668
|
+
- `/artifacts latest`, `/artifacts zip latest`, `/artifacts images`, `/artifacts docs`, `/artifacts search <text>`, and `/artifacts delete <turn-id>` are available in Slack.
|
|
669
|
+
- Unsafe launch profiles require explicit confirmation with `/launch <profile-id> confirm`.
|
|
670
|
+
- Slack does not support Telegram reactions or Telegram webhook transport; typing/status, message edits, attachments, files, DMs, channels, and threads are supported.
|
|
671
|
+
|
|
582
672
|
## Command Examples
|
|
583
673
|
|
|
584
674
|
Switching to an existing thread:
|
|
@@ -760,7 +850,7 @@ Voice transcription uses `OPENAI_API_KEY`, not `CODEX_API_KEY`.
|
|
|
760
850
|
Telegram:
|
|
761
851
|
|
|
762
852
|
- `TELEGRAM_ENABLED`: starts the Telegram adapter. Defaults to `true`.
|
|
763
|
-
- `TELEGRAM_BOT_TOKEN`:
|
|
853
|
+
- `TELEGRAM_BOT_TOKEN`: BotFather token. Required for the Telegram adapter to start.
|
|
764
854
|
- `TELEGRAM_RATE_LIMIT_MIN_INTERVAL_MS`: minimum interval for normal Telegram API sends. Defaults to `80`.
|
|
765
855
|
- `TELEGRAM_EDIT_MIN_INTERVAL_MS`: minimum interval for Telegram message edits. Defaults to `1200`.
|
|
766
856
|
- `TELEGRAM_TRANSPORT`: `polling` or `webhook`. Defaults to `polling`.
|
|
@@ -780,7 +870,7 @@ Telegram:
|
|
|
780
870
|
Discord:
|
|
781
871
|
|
|
782
872
|
- `DISCORD_ENABLED`: starts the Discord adapter. Defaults to `false`.
|
|
783
|
-
- `DISCORD_BOT_TOKEN`:
|
|
873
|
+
- `DISCORD_BOT_TOKEN`: Discord bot token. Required for the Discord adapter to start.
|
|
784
874
|
- `DISCORD_CLIENT_ID`: Discord application/client id used for slash-command registration.
|
|
785
875
|
- `DISCORD_GUILD_IDS`: optional comma-separated guild ids for instant guild slash-command registration.
|
|
786
876
|
- `DISCORD_ALLOWED_GUILD_IDS`: optional guild allow-list before user/group permissions are checked.
|
|
@@ -790,13 +880,39 @@ Discord:
|
|
|
790
880
|
- `DISCORD_AUTO_REGISTER_COMMANDS`: registers slash commands on startup when `DISCORD_CLIENT_ID` is set. Defaults to `true`.
|
|
791
881
|
- `DISCORD_CLI_MIRROR_MODE`, `DISCORD_CLI_MIRROR_MIN_UPDATE_MS`, `DISCORD_NOTIFY_MODE`, `DISCORD_QUIET_HOURS`, and `DISCORD_AUTO_SEND_ARTIFACTS`: optional Discord-specific overrides for the channel-neutral defaults.
|
|
792
882
|
|
|
883
|
+
Slack:
|
|
884
|
+
|
|
885
|
+
- `SLACK_ENABLED`: starts the Slack adapter. Defaults to `false`.
|
|
886
|
+
- `SLACK_BOT_TOKEN`: Slack bot token. Required for the Slack adapter to start.
|
|
887
|
+
- `SLACK_APP_TOKEN`: Slack app-level token for Socket Mode. Required when `SLACK_SOCKET_MODE=true`.
|
|
888
|
+
- `SLACK_SIGNING_SECRET`: Slack signing secret for HTTP Events mode. Required when `SLACK_SOCKET_MODE=false`.
|
|
889
|
+
- `SLACK_SOCKET_MODE`: uses Slack Socket Mode instead of an HTTP Events receiver. Defaults to `true`.
|
|
890
|
+
- `SLACK_PORT`: HTTP receiver port when Socket Mode is disabled. Defaults to `3000`.
|
|
891
|
+
- `SLACK_ALLOWED_TEAM_IDS`: optional Slack workspace allow-list before user/group permissions are checked.
|
|
892
|
+
- `SLACK_ALLOWED_CHANNEL_IDS`: optional channel allow-list before user/group permissions are checked.
|
|
893
|
+
- `SLACK_MESSAGE_CONTENT_ENABLED`: reads regular Slack text messages as prompts. Defaults to `true`.
|
|
894
|
+
- `SLACK_COMMAND`: slash command configured in Slack. Defaults to `/nordrelay`.
|
|
895
|
+
- `SLACK_CLI_MIRROR_MODE`, `SLACK_CLI_MIRROR_MIN_UPDATE_MS`, `SLACK_NOTIFY_MODE`, `SLACK_QUIET_HOURS`, and `SLACK_AUTO_SEND_ARTIFACTS`: optional Slack-specific overrides for the channel-neutral defaults.
|
|
896
|
+
|
|
793
897
|
User management:
|
|
794
898
|
|
|
795
|
-
- Users, groups, Telegram identities, Telegram group-chat access, Discord identities, Discord channel access, and web sessions are stored in `~/.nordrelay/users.json`.
|
|
796
|
-
- Manage users in the WebUI Users page or with `nordrelay user list`, `create-admin`, `create`, `reset-password`, `link-telegram`, `link-discord`, `link-code`, and `
|
|
899
|
+
- Users, groups, Telegram identities, Telegram group-chat access, Discord identities, Discord channel access, Slack identities, Slack channel access, and web sessions are stored in `~/.nordrelay/users.json`.
|
|
900
|
+
- Manage users in the WebUI Users page or with `nordrelay user list`, `create-admin`, `create`, `reset-password`, `link-telegram`, `link-discord`, `link-slack`, `link-code`, `discord-link-code`, and `slack-link-code`.
|
|
797
901
|
- Built-in groups are `admin`, `user`, and `readonly`.
|
|
798
|
-
- Group permissions include `inspect`, `sessions.read`, `sessions.write`, `prompt.send`, `prompt.abort`, `files.read`, `files.write`, `settings.read`, `settings.write`, `auth.manage`, `diagnostics.read`, `logs.read`, `logs.clear`, `queue.read`, `queue.write`, `updates.run`, `system.restart`, `users.read`, `users.write`, and `
|
|
799
|
-
- Custom groups can also restrict access to specific agent ids, workspace roots, Telegram chat ids, and
|
|
902
|
+
- Group permissions include `inspect`, `sessions.read`, `sessions.write`, `prompt.send`, `prompt.abort`, `files.read`, `files.write`, `settings.read`, `settings.write`, `auth.manage`, `diagnostics.read`, `logs.read`, `logs.clear`, `queue.read`, `queue.write`, `updates.run`, `system.restart`, `users.read`, `users.write`, `audit.read`, `peers.read`, `peers.write`, and `peers.connect`.
|
|
903
|
+
- Custom groups can also restrict access to specific agent ids, workspace roots, Telegram chat ids, Discord channel ids, and Slack channel ids.
|
|
904
|
+
|
|
905
|
+
Peers:
|
|
906
|
+
|
|
907
|
+
- `NORDRELAY_PEER_ENABLED`: starts the dedicated peer API. Defaults to `false`.
|
|
908
|
+
- `NORDRELAY_PEER_NAME`: optional human-readable node name shown to paired instances.
|
|
909
|
+
- `NORDRELAY_PEER_HOST`: peer API bind host. Defaults to `127.0.0.1`.
|
|
910
|
+
- `NORDRELAY_PEER_PORT`: peer API port. Defaults to `31979`.
|
|
911
|
+
- `NORDRELAY_PEER_PUBLIC_URL`: optional URL other instances should use to reach this node.
|
|
912
|
+
- `NORDRELAY_PEER_TLS_ENABLED`: serves the peer API over HTTPS with an automatically generated local certificate. Defaults to `true`.
|
|
913
|
+
- `NORDRELAY_PEER_REQUIRE_TLS`: refuses plaintext peer serving on non-loopback hosts. Defaults to `true`.
|
|
914
|
+
- Peer identity, TLS certificate, peers, and invitations are stored under `~/.nordrelay/identity.json`, `~/.nordrelay/tls/`, and `~/.nordrelay/peers.json`.
|
|
915
|
+
- Peer invitations expire after at most 24 hours even if a longer lifetime is requested.
|
|
800
916
|
|
|
801
917
|
Agent selection:
|
|
802
918
|
|
|
@@ -824,8 +940,8 @@ Codex:
|
|
|
824
940
|
- `CODEX_CLI_PATH`: optional explicit path to the Codex CLI executable.
|
|
825
941
|
- `CODEX_USE_BUNDLED_CLI`: set `true` to force the SDK-bundled Codex CLI instead of the host `codex` executable.
|
|
826
942
|
- `CODEX_MODEL`: default model for new threads.
|
|
827
|
-
- `CODEX_SYNC_INTERVAL_MS`: periodic local Codex-state sync interval for active
|
|
828
|
-
- `CODEX_EXTERNAL_BUSY_CHECK_MS`: how often queued
|
|
943
|
+
- `CODEX_SYNC_INTERVAL_MS`: periodic local Codex-state sync interval for active chat sessions. Defaults to `10000`; set `0` to disable.
|
|
944
|
+
- `CODEX_EXTERNAL_BUSY_CHECK_MS`: how often queued chat prompts re-check an active local Codex CLI task. Defaults to `5000`.
|
|
829
945
|
- `CODEX_EXTERNAL_BUSY_STALE_MS`: maximum age for an unclosed rollout task before it is treated as stale instead of active. Defaults to `300000`.
|
|
830
946
|
- `CODEX_SANDBOX_MODE`: default sandbox mode, one of `read-only`, `workspace-write`, `danger-full-access`.
|
|
831
947
|
- `CODEX_APPROVAL_POLICY`: default approval policy, one of `never`, `on-request`, `on-failure`, `untrusted`.
|
|
@@ -948,7 +1064,7 @@ ENABLE_UNSAFE_LAUNCH_PROFILES=true
|
|
|
948
1064
|
CODEX_LAUNCH_PROFILES_JSON=[{"id":"host-full","label":"Host Full Access","sandboxMode":"danger-full-access","approvalPolicy":"never"}]
|
|
949
1065
|
```
|
|
950
1066
|
|
|
951
|
-
Unsafe profiles are intentionally gated.
|
|
1067
|
+
Unsafe profiles are intentionally gated. Chat adapters ask for confirmation before applying them.
|
|
952
1068
|
|
|
953
1069
|
## Security Notes
|
|
954
1070
|
|
|
@@ -956,12 +1072,14 @@ Unsafe profiles are intentionally gated. Telegram asks for confirmation before a
|
|
|
956
1072
|
- Link Telegram accounts only to active NordRelay users that should control agents remotely.
|
|
957
1073
|
- Enable Telegram group/forum chats only when the whole chat context is trusted for the permissions granted to linked users.
|
|
958
1074
|
- Review group permissions before granting `prompt.send`, `prompt.abort`, `files.write`, `settings.write`, `updates.run`, `system.restart`, or `users.write`.
|
|
1075
|
+
- Review peer scopes before granting `peers.write`, `peers.connect`, broad `prompt.send`, or unrestricted workspace roots to a paired instance.
|
|
959
1076
|
- Treat `danger-full-access` as equivalent to shell access on the host.
|
|
960
1077
|
- Treat uploaded files as untrusted input. They are staged inside the active workspace so the selected sandbox policy still matters.
|
|
961
1078
|
- Keep `CODEX_API_KEY`, `HERMES_API_KEY`, `OPENCLAW_GATEWAY_TOKEN`, `OPENCLAW_GATEWAY_PASSWORD`, and `OPENAI_API_KEY` in `~/.nordrelay/nordrelay.env` or host secret management.
|
|
962
1079
|
- In group chats, remember that any linked user with prompt permissions can prompt the selected agent in that chat context.
|
|
963
1080
|
- Use `TOOL_VERBOSITY=summary` or `errors-only` when command output may include sensitive data.
|
|
964
1081
|
- Review and unsafe launch profiles add a Telegram approve/deny gate before each turn starts.
|
|
1082
|
+
- Keep the peer API disabled unless needed. For internet use, expose it only through a firewall, VPN, or hardened reverse proxy; keep TLS enabled and revoke unused peers with `nordrelay peer revoke <peer-id>`.
|
|
965
1083
|
|
|
966
1084
|
## Troubleshooting
|
|
967
1085
|
|
|
@@ -1118,7 +1236,10 @@ npm run build
|
|
|
1118
1236
|
- `src/index.ts`: runtime entrypoint, config load, auth check, state-file writes, polling lifecycle, shutdown.
|
|
1119
1237
|
- `src/bot.ts`: Telegram prompt/session runtime, streaming, file/photo/voice handling, artifacts, and error handling.
|
|
1120
1238
|
- `src/telegram-general-commands.ts`, `src/telegram-agent-commands.ts`, `src/telegram-preference-commands.ts`, `src/telegram-access-commands.ts`, `src/telegram-diagnostics-command.ts`, `src/telegram-update-commands.ts`, `src/telegram-support-command.ts`, and `src/telegram-command-menu.ts`: focused Telegram command groups for start/help/adapters, agent/auth controls, per-chat preferences, access linking, diagnostics/log/version commands, update jobs, diagnostics bundle export, and command menu registration.
|
|
1121
|
-
- `src/channel-adapter.ts`, `src/channel-runtime.ts`,
|
|
1239
|
+
- `src/channel-adapter.ts`, `src/channel-runtime.ts`, `src/channel-command-core.ts`, `src/channel-actions.ts`, and `src/adapter-conformance.ts`: channel descriptors, shared command dispatch/coverage, outbound delivery contracts, channel-neutral responses, and generated feature/command conformance matrices.
|
|
1240
|
+
- `src/discord-bot.ts` and `src/slack-bot.ts`: Discord and Slack bridge runtimes built on the shared channel command core, channel runtimes, rate limiters, access checks, streaming replies, attachments, mirrors, and queue controls.
|
|
1241
|
+
- `src/slack-diagnostics.ts`: Slack readiness probes for token/transport config, auth, registered channel visibility, file-upload readiness, and rate-limit reporting.
|
|
1242
|
+
- `src/user-management.ts`, `src/user-management-types.ts`, `src/user-management-normalize.ts`, and `src/user-management-crypto.ts`: user/group/session/channel-access store with separated DTOs, payload normalization, password/token helpers, and public snapshots.
|
|
1122
1243
|
- `src/config-metadata.ts`: shared setting metadata used by the WebUI settings page and generated `.env.example`.
|
|
1123
1244
|
- `src/support-bundle.ts` and `src/zip-writer.ts`: redacted diagnostics bundle creation with a dependency-free ZIP writer.
|
|
1124
1245
|
- `src/relay-queue-service.ts`, `src/relay-artifact-service.ts`, and `src/relay-external-activity-monitor.ts`: Web runtime queue operations, artifact preview/export/persistence, and external CLI activity mirroring.
|
package/dist/access-control.js
CHANGED
|
@@ -20,6 +20,9 @@ export const ALL_PERMISSIONS = [
|
|
|
20
20
|
"users.read",
|
|
21
21
|
"users.write",
|
|
22
22
|
"audit.read",
|
|
23
|
+
"peers.read",
|
|
24
|
+
"peers.write",
|
|
25
|
+
"peers.connect",
|
|
23
26
|
];
|
|
24
27
|
export const ADMIN_GROUP_ID = "admin";
|
|
25
28
|
export const USER_GROUP_ID = "user";
|
|
@@ -71,6 +74,8 @@ const COMMAND_PERMISSIONS = new Map([
|
|
|
71
74
|
["health", "inspect"],
|
|
72
75
|
["version", "inspect"],
|
|
73
76
|
["channels", "inspect"],
|
|
77
|
+
["peers", "peers.read"],
|
|
78
|
+
["target", "peers.connect"],
|
|
74
79
|
["agents", "inspect"],
|
|
75
80
|
["tasks", "inspect"],
|
|
76
81
|
["progress", "inspect"],
|
|
@@ -148,7 +153,7 @@ export function permissionForCallbackData(callbackData) {
|
|
|
148
153
|
if (callbackData.startsWith("approval_") || callbackData.startsWith("codex_abort:") || callbackData.startsWith("agent_abort:")) {
|
|
149
154
|
return "prompt.abort";
|
|
150
155
|
}
|
|
151
|
-
if (callbackData.startsWith("queue_")) {
|
|
156
|
+
if (callbackData.startsWith("queue_") || callbackData.startsWith("peer_queue_")) {
|
|
152
157
|
return "queue.write";
|
|
153
158
|
}
|
|
154
159
|
if (callbackData.startsWith("artifact_delete")) {
|
package/dist/activity-events.js
CHANGED
|
@@ -11,7 +11,7 @@ export function activityCategoryForType(type) {
|
|
|
11
11
|
return "artifact";
|
|
12
12
|
if (/^(auth|login|logout)/.test(type))
|
|
13
13
|
return "auth";
|
|
14
|
-
if (/^(user_|group_|telegram_chat_|telegram_link|discord_channel_|discord_link|permission_|access_|lock_)/.test(type))
|
|
14
|
+
if (/^(user_|group_|telegram_chat_|telegram_link|discord_channel_|discord_link|slack_channel_|slack_link|peer_|permission_|access_|lock_)/.test(type))
|
|
15
15
|
return "security";
|
|
16
16
|
if (/^(tool_|cli_tool)/.test(type))
|
|
17
17
|
return "tool";
|
|
@@ -32,7 +32,7 @@ export function auditCategoryForAction(action) {
|
|
|
32
32
|
return "security";
|
|
33
33
|
if (/^auth_/.test(action))
|
|
34
34
|
return "auth";
|
|
35
|
-
if (/^(permission_|user_|group_|telegram_|discord_)/.test(action))
|
|
35
|
+
if (/^(permission_|user_|group_|telegram_|discord_|slack_|peer_)/.test(action))
|
|
36
36
|
return "security";
|
|
37
37
|
if (/^(artifact|file)/.test(action))
|
|
38
38
|
return "artifact";
|