A self-hosted bridge between a Lark custom app and the OpenAI Codex CLI. Send a message or image to the bot, let Codex work in a dedicated local repository, and receive the result in the original Lark conversation.
Warning
This project lets chat messages start a local coding agent that can read files and run commands. Use a dedicated machine or OS account, keep the allowlist narrow, and review the security settings before deployment.
- Lark long-connection and HTTPS webhook transports
- Strict sender allowlist based on Lark
open_id - Persistent Codex threads per chat
- Text, rich-text, quoted-message, and multi-image input
- App-server mode with live
/steersupport - Queue priority, cancellation, message recall, and retry handling
- Periodic progress replies for long-running work
- Local image upload through a simple
FEISHU_IMAGE:result protocol - Safe public defaults: workspace-only writes and no sandbox network access
User-facing operational messages are currently written in Chinese. Codex is instructed to answer in the same language as the user.
- Python 3.11 or newer
- Node.js and npm
- A Lark custom app with bot capability enabled
- An installed and authenticated OpenAI Codex CLI
Install Codex CLI and authenticate it:
npm install --global @openai/codex
codex logingit clone https://github.com/Raytto/lark-codex-bot.git
cd lark-codex-bot
python -m venv .venvActivate the environment and install dependencies:
# Linux/macOS
source .venv/bin/activate
# Windows PowerShell
.\.venv\Scripts\Activate.ps1
python -m pip install -r requirements.txtCopy .env.example to .env, then set at least:
LARK_APP_ID=cli_your_app_id
LARK_APP_SECRET=your_app_secret
LARK_ALLOWED_OPEN_IDS=ou_your_open_id
CODEX_MODEL=gpt-5.6-sol
CODEX_REASONING_EFFORT=highUse a model identifier available to the Codex CLI account used by the bot.
Start the bot:
python app.pyThe default long_connection transport does not require a public callback URL.
For webhook mode, set LARK_TRANSPORT=webhook, configure the verification token
and encrypt key, and expose the configured callback path through HTTPS.
Enable bot capability and grant the app permissions to:
- receive direct messages sent to the bot;
- send messages as the app;
- add and remove message reactions;
- read individual messages, including edited and quoted content;
- download and upload image/file resources.
Subscribe to these events when using webhook mode:
im.message.receive_v1im.message.recalled_v1im.message.reaction.created_v1im.message.reaction.deleted_v1
Publish the Lark app after changing permissions or event subscriptions.
LARK_ALLOWED_OPEN_IDS is mandatory. Messages from other senders are discarded
before their content is parsed, queued, stored, or sent to Codex.
The public configuration defaults to:
CODEX_SANDBOX_MODE=workspace-write
CODEX_APPROVAL_POLICY=never
CODEX_WORKSPACE_NETWORK_ACCESS=falseThis matches Codex's local security model: workspace-write limits modifications to the active workspace and network access remains disabled unless explicitly enabled. The bot is unattended, so approval requests cannot be answered in the terminal; keep network and host access disabled unless the deployment is fully isolated and trusted.
Supported sandbox modes are read-only, workspace-write, and
danger-full-access. Enabling danger-full-access is an explicit opt-in and
removes the filesystem sandbox.
Use CODEX_EXTRA_INSTRUCTIONS for deployment-specific guidance. Do not put
credentials or private identifiers in that value.
/newor/clear: start a fresh Codex thread/stop: cancel the running task/priority: move the sender's next task to the front of the waiting queue/steer: send the next message into the currently running app-server turn/status: show the current thread and queue state/help: show command help
The bot adds a Get reaction while processing and replaces it with DONE after
successful completion.
To upload a local image to Lark, Codex must include a line like this in its final message:
FEISHU_IMAGE: outputs/result.png
Paths must stay inside the repository. See
knowledge/feishu_images.md for the complete
protocol.
The bot stores its SQLite message/session state and downloaded attachments under
.state/. That directory, .env, virtual environments, output files, and logs
are ignored by Git and must not be published.
python -m unittest discover -s tests -v