ringclaw / dsh-ringcentral

Listed

Plugin for integrating RingCentral with DeepSeek Harness (dsh)

mainOther View source

Installation

npx @deepseek-ai/dsh plugin --profile ringcentral add dsh-ringcentral

This command is generated from the GitHub repository address. Inspect the upstream README and source before running it; pin a release or commit when reproducibility matters.

README

Maintainer-authored documentation snapshot.

View on GitHub ↗
Commit f9c3a2eSynced Aug 18, 2026

This README snapshot could not be refreshed during the latest directory sync.

dsh-ringcentral

RingCentral Team Messaging IM channel plugin for deepseek-harness (dsh). It turns a RingCentral Bot Add-in into a first-class frontend for a dsh agent: inbound posts from RingCentral chats drive the agent loop, and assistant replies flow back as threaded RingCentral posts.

English | 中文说明

Architecture

RingCentral user ──▶ WebSocket (PostAdded) ──▶ im-ringcentral ──▶ ctx.agents ──▶ dsh agent loop ──▶ LLM
                                                │                                     │
                                                └── admission / session / event ◀────┘
                                                     (assistant reply ──▶ RingCentral post, threaded)

The plugin is a pure Cordis plugin following the dsh "Plugins, not loop changes" principle. It speaks the RingCentral Team Messaging v1 REST API + WebSocket subscription stream directly (no external SDK) and reuses the host dsh services for agents, sessions, models, compaction, and tool presentation.

Install

1. Via dsh plugin manager

# install into a profile
npx @deepseek-ai/dsh plugin --profile ringcentral add dsh-ringcentral

# start
export RC_BOT_TOKEN="your-bot-jwt"
export DEEPSEEK_API_KEY="your-deepseek-key"
npx @deepseek-ai/dsh --profile ringcentral

Or run the bundled installer: sh install.sh.

2. Local path

cd /path/to/dsh-ringcentral
pnpm install && pnpm build
npx @deepseek-ai/dsh plugin --profile ringcentral add /path/to/dsh-ringcentral
export RC_BOT_TOKEN="your-bot-jwt"
npx @deepseek-ai/dsh --profile ringcentral

3. --patch development mode

The --patch overlay loads the plugin from a local absolute path without installing it into a profile. Generate the machine-local patch first, then boot:

cd /path/to/dsh-ringcentral
pnpm install && pnpm build        # dist entry (npx dsh cannot resolve .js -> .ts)
node scripts/gen-dev-patch.mjs    # writes cordis.local.yml with the real path
export RC_BOT_TOKEN="your-bot-jwt"
npx @deepseek-ai/dsh web --patch ./cordis.local.yml

Use pnpm dev (tsc --watch) while iterating: the loader hot-reloads the plugin whenever dist/ changes. Pointing the patch at src/index.ts only works inside a deepseek-harness source tree (pnpm dsh), not with the npx-installed package.

RingCentral bot setup

  1. Sign in at https://developers.ringcentral.com/.
  2. Create an app with the Bot platform type.
  3. Grant at least: TeamMessaging, ReadAccounts, WebSocketsSubscription.
  4. Install or publish the bot to your RingCentral account.
  5. Copy the bot JWT and use it as RC_BOT_TOKEN.

Optional owner credentials (JWT REST API app for your own account, with TeamMessaging + WebSocketsSubscription + ReadMessages) give ringcentral_get_recent_messages owner read fallback and outbound owner fallback. The history tool always reads through the bot client (RC_BOT_TOKEN) first; without owner credentials it uses only the bot client (chats the bot is a member of).

Configuration

Config follows dsh practice: the cordis config tree is the single source (profile cordis.patch.yml / cordis.yml), with Schema defaults applied automatically. The plugin reads environment variables directly only for secrets: RC_BOT_TOKEN, RC_SERVER_URL, RC_USER_CLIENT_ID, RC_USER_CLIENT_SECRET, RC_USER_JWT_TOKEN. To drive any other setting from an environment variable, use cordis ${VAR} interpolation in your config, e.g. dmPolicy: ${RC_DM_POLICY:-pairing}.

ConfigTypeDefaultDescription
botTokenstringrequiredBot static JWT (env: RC_BOT_TOKEN)
ownerCredentials.clientId / clientSecret / jwtstring-Owner JWT (env: RC_USER_*)
serverstringhttps://platform.ringcentral.comAPI server (env: RC_SERVER_URL)
botExtensionIdstringauto-detectedBot person id for mention/self-echo detection
dmPolicyenumpairingDM handling: disabled, allowlist, pairing, open
allowFromstring[][]Stable person ids allowed in DMs; open requires ["*"]
dangerouslyAllowEmailMatchingbooleanfalseMatch allowFrom against email aliases
groupPolicyenumdisabledTeam/Everyone handling: disabled, allowlist, open
teamsmap{}Per-chat Team config: allow, requireMention, systemPrompt, users
groupDmEnabledbooleanfalseEnable Group DM conversations
groupDmChannelsmap{}Per-chat Group DM allowlist
threadRequireMentionbooleantrueRequire mention for thread follow-ups
noThreadChannelsstring[][]Chat ids where replies are unthreaded
replyToModeenumfirstoff, first, or all
processingPlaceholder.enabledbooleanfalsePost 👀 while the agent works
processingPlaceholder.editDelaySecondsnumber2Delay before 👀 becomes
attachments.enabled / maxCount / maxBytes-true / 5 / 5242880Inbound attachment download
historyMessageLimitnumber250Default record count for the history tool
homeChannelstring-Fallback target for the history tool
requireMentionbooleantrueGlobal mention gate for Team/Everyone and Group DM (per-chat requireMention overrides)
textChunkLimitnumber4000Max chars per outgoing post
allowBotsbooleanfalseAdmit bot-authored inbound posts
provider / modelstringhost defaultLLM route (fallback chain: per-peer prefs → config → settings.yaml → host)
presetstring-Agent preset id
cwdstringprocess.cwd()Agent working directory
sessionIdleTimeoutnumber1800000Idle session eviction (ms)
showToolResultsbooleanfalseShow successful tool results (errors always show)
debugbooleanfalseDebug logging

Commands

CommandDescription
/new (/reset, /clear)Start a new session (clear context)
/compactCompress session history (summary replaces old records)
/modelShow or switch the model
/stopAbort the current generation
/rc-pingConnectivity test
/rc-versionPlugin version
/rc-statusCurrent session status
/rc-helpList all commands

Session routing

sessionKey: ringcentral:<accountScopeKey>:<scope>:<peerId> where scope is direct (peer = person id), group (peer = Group DM chat id), or channel (peer = Team/Everyone chat id), and accountScopeKey is a SHA-256 fingerprint of server + bot token. The SessionId is derived deterministically (SHA-256), so the same user/chat always routes to the same session and survives restarts. Resolution order: in-process reuse → persisted resume → fresh create.

Design principles

  • Pure Cordis plugin — follows dsh "Plugins, not loop changes".
  • Declarative depsinject = ['agents']; tools/compaction/presets are optional seams.
  • Session isolation — one agent per RingCentral peer.
  • Mini-Markdown outbound — replies are converted to RingCentral Mini-Markdown and chunked.
  • Threading — replies honor replyToMode with owner fallback and unthreaded retry.
  • Idle eviction — inactive agents are disposed automatically.
  • Defensive degradation — missing tools/presets/owner credentials never crash the plugin.

Not in v1 (planned follow-ups)

  • Adaptive Card / note / calendar / task artifact tools
  • Cron and out-of-process notification sender
  • Multi-account support
  • Native streaming (RingCentral has no stream API; the processing placeholder is the typing affordance)

Local development

pnpm install
pnpm build          # or: pnpm dev (watch)
pnpm test
pnpm typecheck

# run against the npx-installed dsh
export RC_BOT_TOKEN="xxx"
node scripts/gen-dev-patch.mjs
npx @deepseek-ai/dsh web --patch ./cordis.local.yml

cordis.dev.yml is the committed template; scripts/gen-dev-patch.mjs replaces the /path/to/dsh-ringcentral placeholder with the machine's absolute path and writes the gitignored cordis.local.yml.

Troubleshooting

SymptomLikely causeFix
Plugin not startingRC_BOT_TOKEN missingSet RC_BOT_TOKEN or botToken in cordis.patch.yml
Bot never replies in a TeamgroupPolicy: disabled or no mentionAllowlist the chat under teams and @-mention the bot
DM ignoreddmPolicy or pairing already claimedCheck dmPolicy / allowFrom; pairing is claimed by the first DM sender
History tool returns nothingChat not visible to bot or ownerReads try the bot first, then the owner; pass a bare chat id or channel:<chatId> and make sure one client is a member
Replies not threadedreplyToMode: off or noThreadChannelsCheck replyToMode and noThreadChannels
Legacy env rejectedRC_ALLOWED_USER_EMAILS etc.Behavioral config lives in the cordis config tree now — use allowFrom / teams (see migration errors in logs)

License

MIT

Project files and signals

Shown items are public repository signals detected in the directory snapshot.

TestsDetected

Repository information

Language
TypeScript
License
MIT
Latest release
v0.1.0
Last updated
Aug 18, 2026, 8:29 AM

Install deliberately

Review source code, permissions, lifecycle hooks, dependencies and network access. Test untrusted plugins in an isolated environment.