{"slug": "put-claude-code-and-codex-inside-wechat-lark-and-dingtalk-with-langbot-runner", "title": "Put Claude Code and Codex Inside WeChat, Lark and DingTalk with LangBot Runner Plugins", "summary": "The LangBot project released version 4.11, which removes the nine built-in runners from src/langbot/pkg/provider/runners/ and turns runners into installable plugin components, letting teams run Claude Code and Codex agents from WeChat Work, Lark and DingTalk group chats. The release adds a RunnerRegistry that discovers plugin runners over LIST_RUNNERS and generates ids as plugin:author/plugin_name/runner_name, plus a twelve-package adapter layer under src/langbot/pkg/platform/adapters/, with official ClaudeCodeAgent and CodexAgent plugin ids. Runner plugins execute in a separate plugin-runtime container, making deployment a two-container setup.", "body_md": "A team already lives in Claude Code and Codex — repos, shell, MCP servers on their own machines. Colleagues should reach that same power from **WeChat Work, Lark and DingTalk** group chats, without a terminal.\n\nOn 4.10 that was awkward — not inbound: 4.10.11 already ships `openclaw_weixin`, `lark`, `dingtalk` under `src/langbot/pkg/platform/sources/`. The **processing** side was the wall: nine built-in runners under `src/langbot/pkg/provider/runners/` (`localagent.py`, `difysvapi.py`, … `weknoraapi.py`), so adding Claude Code meant patching LangBot or wrapping the CLI in an HTTP service outside the bot.\n\n4.11 flips that: a Runner is a plugin, and the platform is only the **event source**. Support depends on the adapter and platform — check the support matrix first.\n\n**New in 4.11: the built-in runners are gone.** `src/langbot/pkg/provider/runners/` holds ten files at `v4.10.11` and **does not exist** at `v4.11.0`; `src/langbot/pkg/provider/` keeps only `modelmgr/`, `session/`, `tools/` (`git ls-tree`, both revisions).\n\n**A Runner is a plugin component.** The runtime reports installed plugins' runners over `LIST_RUNNERS`; the host discovers and caches them in `RunnerRegistry` (`src/langbot/pkg/agent/runner/registry.py:20,24,152`), generating ids as `plugin:author/plugin_name/runner_name` (`src/langbot/pkg/agent/runner/id.py:24-27`) and rejecting anything without that prefix (` id.py:52-57`; `PROTOCOL_V1.md` §13).\n\n**The manifest is the contract**: `id`, `name`, `label`, `description`, `capabilities`, `permissions`, `config_schema`, `metadata` (§4.2); `capabilities` is a typed boolean model for UI and resource projection, **not** a permission grant, and `permissions` is the access ceiling, intersected with the binding policy.\n\n**Official ids**: `plugin:langbot-team/ClaudeCodeAgent/default`, `plugin:langbot-team/CodexAgent/default` (`docs/agent-runner-pluginization/OFFICIAL_RUNNER_PLUGINS.md:33-34`).\n\n**New in 4.11: the adapter layer.** `src/langbot/pkg/platform/adapters/` is absent at `v4.10.11`; 4.11 splits it into twelve packages with `manifest.yaml`, `adapter.py`, `event_converter.py`, and the Lark manifest declares `kind: MessagePlatformAdapter` (`src/langbot/pkg/platform/adapters/lark/manifest.yaml:1-4,13`). The inbound **file inventory is unchanged**: between `v4.10.11` and `v4.11.0`, all 22 files under `src/langbot/pkg/platform/sources/` are modifications — no additions, no deletions — so no new platform arrived here.\n\n**Where config lands**: `ai.runner.id` stores the runner id and `ai.runner_config[<runner_id>]` its settings (`src/langbot/templates/metadata/pipeline/ai.yaml:6-18`), so switching runners keeps earlier settings.\n\nRunner plugins execute in a **separate plugin-runtime container**, so this is a two-container setup (local demo values — replace them):\n\n```\ndocker network create lang7-411\ndocker run -d --name lang7-411-core --network lang7-411 -e BOX__ENABLED=false \\\n  -p 15400:5300 -v \"$PWD/deploy/411/data:/app/data\" rockchin/langbot:v4.11.0\ndocker run -d --name lang7-411-runtime --network lang7-411 --network-alias langbot_plugin_runtime \\\n  -v \"$PWD/deploy/411/data/plugins:/app/data/plugins\" \\\n  rockchin/langbot:v4.11.0 uv run --no-sync -m langbot_plugin.cli.__init__ rt\n```\n\nThe admin account starts as `admin@langbot.local`; the password is a **local demo value — replace it**.\n\n**Step 1 — install from the marketplace.** UI: Extensions → Extension Marketplace (`web/src/i18n/locales/zh-Hans.ts:337-341`); CLI: `POST /api/v1/plugins/install/marketplace` with `{plugin_author, plugin_name}`, returning `{task_id}` for task `plugin-install-marketplace`; the record carries `install_source=marketplace` (`src/langbot/pkg/api/http/controller/groups/plugins.py:923-960`). Here we installed `langbot-team/LocalAgent`; the Claude Code and Codex plugins use the same door (repo [langbot-plugins](https://github.com/langbot-app/langbot-plugins), `Runner/claude-code-agent`, `Runner/codex-agent`).\n\n**Step 2 — confirm where it landed.** The artifact is **not** in the mounted `plugins/` directory but inside the runtime container at `/app/data/plugin-runtime/artifacts/sha256/<digest>/code/` (`manifest.yaml`, `main.py`, `pkg/`, `components/`, `CERTIFICATION.md`), while the host-mounted `plugins/` stays empty (observed 2026-10-16); `<digest>` is the recorded `artifact_digest`. Three checks: the API (` GET /api/v1/plugins` returns a `{plugins: [...]}` array containing it, `plugins.py:387-397`); the database (a `plugin_settings` row holding `artifact_digest`, `runtime_revision`, `install_source`, `enabled`, `src/langbot/pkg/entity/persistence/plugin.py:12-35,46-51`); and the logs — `Mounting plugin langbot-team/LocalAgent...` → `Initializing Runner component: default` → `Component default initialized, instance type: DefaultRunner` (observed 2026-10-16). The point: the runtime instantiates a **component instance** and the Runner capability hangs off it.\n\n**Step 3 — pick the Runner in the pipeline.** In the pipeline editor open AI capabilities (`web/src/i18n/locales/zh-Hans.ts:1941`) and find the stage card labelled \"运行方式\" (` src/langbot/templates/metadata/pipeline/ai.yaml:7-9`) with its required \"运行器\" dropdown (`:14-18`). The value is the full runner id, e.g. `plugin:langbot-team/LocalAgent/default`; for Claude Code, `plugin:langbot-team/ClaudeCodeAgent/default`. Here the LocalAgent block at `ai.runner_config[<runner_id>]` read `timeout: 300`, `max-tool-iterations: 100` (observed 2026-10-16).\n\n**Step 4 — connect the chat platform as an event source.** Connect a WeChat Work, Lark or DingTalk adapter; events arrive, event bindings route them into a pipeline, and the selected Runner does the work — one bot, several pipelines, each free to use a different Runner.\n\nClaude Code and Codex settings come from their READMEs: `command` defaults to `claude` / `codex`, `timeout` to 300 / 1800 seconds, plus `workspace`, `ssh-target`, `mcp-servers-json` (`Runner/claude-code-agent`, `Runner/codex-agent`).\n\n**API**: `GET /api/v1/plugins` contains `langbot-team/LocalAgent` with `enabled` true. **Database**: digest and revision persisted — values observed here:\n\n```\nSELECT plugin_author, plugin_name, artifact_digest, runtime_revision, install_source, enabled\nFROM plugin_settings;\n-- langbot-team|LocalAgent|2d2ce17055d70dd7736e6902595be3262992fd1598a00bd9d79d19fef1c16329|1|marketplace|1\n```\n\n**Runtime container**: the same `ls` shows the files listed above while the host-mounted `plugins/` stays empty; an empty result means the wrong layer. **Pipeline**: `ai.runner.id` must start with `plugin:` (`web/src/app/home/pipelines/pipeline-config-safety.ts:7-25`) and `ai.runner_config` must hold an object keyed by that id. Then send a real message and confirm the reply comes from the installed Runner.\n\n`src/langbot/pkg/platform/sources/` file set matches 4.10.11 — all 22 files are modifications, none added or removed — and what 4.11 adds is the `platform/adapters/` event-adapter layer; the adapter plus the event binding decides whether a platform works, not the Runner. The support matrix in `{space_url}/api/v1/marketplace/plugins/download/{author}/{name}/{version}` (`src/langbot/pkg/plugin/connector.py:1795-1797`); installs from GitHub or a local archive record `github` / `local`.` plugin_settings.artifact_digest` — here the two LocalAgent 0.2.1 digests `ClaudeCodeAgent` defaults `dangerously-skip-permissions` to `true` (`false` restores Claude Code's own checks; LangBot has no interactive approval flow today) and `CodexAgent` to `approval-policy=never` / `sandbox-mode=danger-full-access`. Trusted workspaces only.` ask_user_question` into `interaction.requested` for the adapter to render as a card; the CLI stops while the user answers, and the answer starts a new run resuming the same session.`PROTOCOL_V1.md` §13).`install_info._certification` read `verification: \"invalid\"` with `certificate_id: null`, while the marketplace reported `certificate_status: \"issued\"` — do not assume local verification passed because a plugin is listed (see article 4).\nIn 4.11 a Runner is not shipped with LangBot but installed from the marketplace, configured in the app, selected per pipeline. The platform delivers the event; the Runner decides how it is processed — a local CLI agent (Claude Code, Codex, ACP) or a service runner such as Dify, Coze, n8n, Langflow or DeerFlow.\n\nPrimary reference: the pinned migration doc [pipeline-migration-config-map.zh-CN.md](https://github.com/langbot-app/LangBot/blob/master/docs/pipeline-migration-config-map.zh-CN.md), which also lists the minimum Runner plugin versions the migrator requires; the [v4.11.0 release page](https://github.com/langbot-app/LangBot/releases/tag/v4.11.0) has the notes. Plugins are also listed in `Runner/` in [langbot-plugins](https://github.com/langbot-app/langbot-plugins).\n\nNext: if your instance was upgraded from 4.10, that old config landing in the new shape is article 3 — the migration touches `ai.runner.runner`, `ai.runner.id` and `ai.runner_config` together. For a hosted environment, Cloud is worth a separate look (`https://space.langbot.app`).", "url": "https://wpnews.pro/news/put-claude-code-and-codex-inside-wechat-lark-and-dingtalk-with-langbot-runner", "canonical_source": "https://dev.to/rockchinq/put-claude-code-and-codex-inside-wechat-lark-and-dingtalk-with-langbot-runner-plugins-350f", "published_at": "2026-10-17 12:25:16+00:00", "updated_at": "2026-10-17 12:34:38.632514+00:00", "lang": "en", "topics": ["ai-agents", "ai-tools", "developer-tools", "agent-protocols"], "entities": ["LangBot", "Claude Code", "Codex", "WeChat Work", "Lark", "DingTalk", "langbot-team", "langbot-plugins"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/put-claude-code-and-codex-inside-wechat-lark-and-dingtalk-with-langbot-runner", "markdown": "https://wpnews.pro/news/put-claude-code-and-codex-inside-wechat-lark-and-dingtalk-with-langbot-runner.md", "text": "https://wpnews.pro/news/put-claude-code-and-codex-inside-wechat-lark-and-dingtalk-with-langbot-runner.txt", "jsonld": "https://wpnews.pro/news/put-claude-code-and-codex-inside-wechat-lark-and-dingtalk-with-langbot-runner.jsonld"}}