Skip to content

GxFn/LarkRemote

Repository files navigation

Lark Remote

Control, observe, and take over local Codex sessions from Feishu/Lark.

Codex Marketplace Node

中文


Why

Codex is strongest when it can work inside your local project, but you are not always sitting at the Mac where Codex Desktop is running. Lark Remote bridges that gap: Codex keeps running locally, while Feishu/Lark becomes the lightweight remote control surface.

The default product shape is narrow on purpose:

Codex Desktop session
   |
   v
Local Lark Remote bridge
   |
   v
Feishu/Lark bot and control console
   |
   v
Observe, choose, or take over local Codex sessions

The bridge is local-first. Existing Codex chat history is not sent to Feishu/Lark during startup. Feishu/Lark users must be allowed before project/session takeover is available, and native Codex permission dialogs stay on the Mac.

This repository is a development workspace for the Lark Remote Codex plugin. The installable marketplace plugin lives in plugins/codex-lark-remote/; the repository root keeps tests, release notes, and development-only scripts outside the marketplace scan surface.

Install

First-time users do not need to clone this repository.

Codex Marketplace CLI

Install the approved marketplace artifact:

npx codex-marketplace add GxFn/LarkRemote/plugins/codex-lark-remote --plugin

To pin the reviewed release:

npx codex-marketplace add https://github.com/GxFn/LarkRemote/tree/v0.3.0/plugins/codex-lark-remote --plugin

Then restart or refresh Codex if the plugin list does not update immediately.

Codex Desktop GitHub Install

If Codex asks for a GitHub target or direct artifact path, use the plugin subdirectory:

https://github.com/GxFn/LarkRemote/tree/v0.3.0/plugins/codex-lark-remote

If the Codex dialog separates source, ref, and sparse path, fill it like this:

Source:
https://github.com/GxFn/LarkRemote.git

Git ref:
v0.3.0

Sparse path:
plugins/codex-lark-remote

Enable codex-lark-remote from the plugin list after installation.

Marketplace Source

This repository includes .agents/plugins/marketplace.json. It declares the codex-lark-remote marketplace with a single plugin entry that points at ./plugins/codex-lark-remote. Use main only when you intentionally want unreleased changes.

Getting Started

The short successful path is:

  1. Install and enable the plugin in Codex.
  2. Create a Feishu/Lark internal app and copy its App ID/App Secret.
  3. Tell Codex copied or 已复制; Codex reads the clipboard and calls lark_configure.
  4. Let Codex run lark_check_auth and lark_verify_setup.
  5. Verify long-connection Event Configuration and Callback Configuration in the Feishu/Lark Open Platform while the bridge is running.
  6. Return to Codex and explicitly approve connecting the current Codex conversation to Lark Remote.
  7. Send whoami to the bot from Feishu/Lark, then add the returned senderId to lark.allowedUsers.
  8. In Feishu/Lark, send console, choose a project/session, and use takeover 1 or the card buttons.

Daily use after setup is simpler: start Lark Remote from a trusted Codex conversation, open the Feishu/Lark console, choose a session, then send ordinary coding requests after takeover is active.

Configure Feishu/Lark

Create the bot app on the platform you want to connect:

  1. Open Feishu Open Platform or Lark Open Platform.
  2. Use lark.domain: "feishu" for Feishu China, which is the default. Use lark.domain: "lark" for international Lark. App ID/App Secret must come from the same Open Platform domain; Feishu and Lark credentials are not interchangeable.
  3. Create an internal/custom app.
  4. Enable the bot capability.
  5. In Credentials & Basic Info, copy App ID and App Secret.
  6. In Event Configuration, choose long connection/WebSocket and subscribe to im.message.receive_v1.
  7. In Callback Configuration, choose long connection/WebSocket and subscribe to card.action.trigger. Keep the Lark Remote bridge running when you click verify/save.
  8. Add the message receive, send/reply, and card interaction permissions requested by the platform, then publish or enable the app for your tenant.

Copy the credentials to the clipboard in this shape:

Feishu/Lark app:
- domain: feishu
- appId: cli_xxx
- appSecret: xxx

Allowed users:
- allowedUsers: []

Optional takeover tuning:
- takeover: { projectLimit: 20, selectionTtlMs: 600000 }

Optional startup intro:
- startup: { receiveId: "oc_xxx", receiveIdType: "chat_id", once: true }

For international Lark, change domain to lark and use credentials created at https://open.larksuite.com.

Private runtime config is stored outside the repository:

~/.codex-lark-remote/config.json

Do not commit that file. For first private setup, allowedUsers: [] is only a temporary discovery state. After whoami works, add the returned sender id before using full project/session takeover.

startup.receiveId is optional. If configured, the bridge proactively sends a startup intro card to that chat. Without it, the first allowed Feishu/Lark message supplies the chat_id, receives the intro once, and becomes the remembered startup target.

Start With The Console

The Feishu/Lark side has one main entry point: the natural-language console. After the bridge is connected, send console or click the console button on the startup card.

Console display language is bound per Feishu/Lark chat. Enter with English to keep later console cards in English; enter with Chinese to keep them in Chinese. Sending a control phrase in the other language switches that chat's later display language.

Useful console phrases:

console
project list
session list
enter project 1
observe session 2
takeover 1
status
whoami
commands on
commands off
handoff off
close Lark connection

The same controls also work in Chinese: 控制台, 项目列表, 会话列表, 进入项目 1, 观察会话 2, 接管 1, 状态, and 关闭飞书连接.

After takeover, the chat switches to thread-dispatch mode. Ordinary Feishu/Lark messages are stored as remote commands, routed by the local bridge runner, and delivered to the selected Codex session through the local route/dispatch executor. The Codex conversation that started Lark Remote remains the locked control-window identity, but routine dispatch no longer depends on starting a fresh codex exec control-window turn or asking that turn to call MCP tools.

The JavaScript bridge still intercepts deterministic keywords and card actions such as console, status, observe off, exit handoff, close Lark connection, and the control: / 控制: prefix. Other text, including project/session wording and dispatch: / 派发: text, is passed to the local route/dispatch executor, which uses the stored remote-command state and the locked control-window target to choose the next Lark Remote action.

Start From Codex

From a trusted Codex conversation, ask:

Start codex-lark-remote.

Codex asks for explicit consent before storing local routing state for this thread in the local bridge. Existing chat history is not sent to Feishu/Lark. After you confirm, the plugin starts or reuses the bridge and opens the Feishu/Lark control path.

When a Codex thread is attached, handoff uses the exact thread id or session path supplied by Codex. It does not guess the nearest conversation by workspace path. The Codex conversation that starts the connection is the dedicated control window; Feishu/Lark can later choose another allowed local session as the target from the console.

On macOS, the bridge starts caffeinate -dimsu while handoff is active so the Mac can keep working with the display off. Set handoff.keepAwake to false in ~/.codex-lark-remote/config.json if you prefer to manage sleep manually.

How It Works

Local Bridge

The plugin MCP server runs inside Codex and starts a separate local bridge process. The bridge owns Feishu/Lark WebSocket delivery, event parsing, queue state, startup notices, observation streams, and handoff routing.

Target Selection

Feishu/Lark controls target selection with console, windows, project list, and takeover. The bot first lists local Codex projects from session records, then lists sessions/windows inside the chosen project. These are Codex session records, not macOS window handles.

Observation And Takeover

Observation is read-only. Use observe, observe <number>, and observe off to stream progress from another Codex session without routing Feishu/Lark input into that session. Observation replies include each newly appended user prompt as a short User prompt: separator before later Codex progress, so separate turns do not collapse into one continuous assistant stream.

Takeover is write-capable after confirmation. Full-project takeover requires a non-empty lark.allowedUsers allowlist. Ordinary Feishu/Lark messages are queued by the bridge runner, routed locally, and delivered to the selected target Codex session. If the target session is active, Lark Remote still queues the dispatch as a higher-priority delivery request instead of failing just because the target is busy. During takeover, prompts that Lark Remote itself sent from Feishu/Lark are not echoed back; prompts appended by other sources, such as automation or local Codex input, are echoed as User prompt: separators.

The dedicated control Codex window provides the locked local identity and an explicit manual/diagnostic fallback. Normal runtime dispatch uses the bridge runner's local route endpoint, then calls local bridge endpoints such as /bridge/dispatch/execute, /bridge/remote-command/reply, or observation and target-selection endpoints. The focused Lark Remote MCP tools lark_route_remote_command, lark_dispatch_remote_command, lark_record_dispatch, lark_request_clarification, and lark_reply_remote_command remain available for explicit control-window diagnostics or recovery, but they are no longer invoked from codex exec for every Feishu/Lark message.

Behavior And Boundaries

Remote replies are optimized for coding in chat:

  • Final Codex answers are sent back as normal text.
  • Long answers are split across multiple Feishu/Lark messages.
  • Progress replies hide internal task ids by default.
  • Normal shell commands and Output: are hidden by default.
  • commands on shows command summaries; commands off hides them again.
  • Risky commands are always shown with a Warning: line.
  • Source inspection output from cat, nl, sed, grep, and normal rg searches is summarized instead of pasted in full.
  • Secrets in command text are redacted before they are sent to Feishu/Lark.

Lark Remote takes over the conversation stream, not the native Codex Desktop UI. Feishu/Lark cannot click permission dialogs, MCP approvals, sandbox-escalation prompts, network/install approvals, or other native Codex UI popups. When Codex hits one of those boundaries, it should send a clear Feishu/Lark message explaining what approval is needed and where to approve it.

If the selected target Codex session is already working, Lark Remote still queues the Feishu/Lark message as a target dispatch request. It fails closed only when the bridge cannot address or queue the selected target session.

Repository Layout

Path Purpose
./ Installable Codex plugin bundle.
bin/ MCP server and local bridge entrypoints.
src/ Bridge, Feishu/Lark, handoff, observer, presenter, and runner modules.
skills/ Codex skill instructions bundled with the plugin.
config/example.config.json Example private runtime config shape.
test/ Node test suite.

Development

For local development, register this repository as a local marketplace:

[marketplaces.gxfn]
source_type = "local"
source = "/absolute/path/to/LarkRemote"

[plugins."codex-lark-remote@gxfn"]
enabled = true

Run tests before publishing:

npm test

The marketplace submission is the nested plugin directory. Keep development tests, release scripts, and generated artifacts out of plugins/codex-lark-remote/.

Troubleshooting

Symptom Check
lark_* tools are missing Refresh or re-enable the plugin, then start a new Codex conversation.
Dispatch says bridge state is unavailable Restart Lark Remote so the runner can read the current local bridge state, then resend the retained Feishu/Lark message.
status says websocket disabled Confirm appId, appSecret, and lark.domain in ~/.codex-lark-remote/config.json.
Feishu/Lark replies twice Stop stale bridge processes or duplicate plugin installations.
Codex edits the plugin cache Start handoff from a Codex conversation whose cwd is the project you want to edit.
Auth fails for international users Use lark.domain: "lark" and credentials from https://open.larksuite.com.

About

Codex plugin for controlling, observing, and taking over local Codex sessions from Feishu/Lark through a local-first bridge.

Topics

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors