A local-first web console for controlling desktop Codex sessions from a browser, phone, or Feishu bot.
The project is designed for long-running development tasks where the actual work happens on your desktop, while your phone acts as a lightweight control surface for status checks, approvals, follow-up instructions, and interrupts.
- Runs a local web terminal for Codex sessions.
- Provides a mobile console with realtime WebSocket updates.
- Supports Feishu private-chat commands as a mobile entry point.
- Sends short-lived mobile console links instead of exposing the main access token.
- Supports task continuation, interrupt, approvals, and supplemental input.
- Uses PM2 helpers for desktop background services.
- Includes a PowerShell command watchdog for commands that may run too long.
Phone Feishu chat
-> Feishu bot bridge
-> local web service on desktop
-> Codex app-server / Codex CLI
-> realtime WebSocket mobile console
-> status, approval, interrupt, and final result back to phone
Feishu is used as the notification and command entry channel. The mobile web console is used for realtime output, continuing input, interrupting tasks, and handling blocking interactions.
- Node.js 22+
- npm
- Codex CLI installed and available in
PATH - A Feishu/Lark app if you want Feishu integration
- Tailscale, LAN, or another private network path if your phone is not on the same machine/network
git clone https://github.com/Robin-fang611/codex-feishu-mobile-control.git
cd codex-feishu-mobile-control
npm install
cp .env.example .env
npm run check
npm run startOpen:
http://127.0.0.1:3210
Set ACCESS_TOKEN in .env before exposing the service beyond localhost.
- Install Tailscale on the desktop and phone.
- Log in to the same Tailnet.
- Set
.env:
HOST=0.0.0.0
TAILSCALE_ONLY=true
MOBILE_PUBLIC_BASE_URL=http://<desktop-tailscale-ip>:3210- Start services:
npm run remote:start
npm run remote:status- On the phone, open the mobile console link returned by Feishu or visit:
http://<desktop-tailscale-ip>:3210
Create a Feishu app, enable bot capability and event subscription, then configure .env:
FEISHU_APP_ID=
FEISHU_APP_SECRET=
FEISHU_SESSION_RUNNER_MODE=app_server
FEISHU_DEFAULT_CWD=/path/to/your/workspace
FEISHU_REQUIRE_BIND=trueYou can also write credentials with:
npm run feishu:config -- -AppId <your_app_id> -AppSecret <your_app_secret>Start the full remote stack:
npm run remote:start
npm run remote:statusUseful commands in Feishu private chat:
新会话
状态
控制台
中断
继续 <your instruction>
待处理
/approve <ID>
/reject <ID>
/reply <ID> <text>
Any other text is treated as a Codex task prompt.
npm run check # Syntax checks + web build
npm run test:app-server-interactions # app-server interaction smoke
npm run test:feishu-interactions # Feishu command smoke
npm run remote:start # web service + Feishu bridge + watchdog
npm run remote:restart # restart all remote services
npm run remote:status # inspect all services
npm run remote:stop # stop all remote services
npm run command:watchdog -- -CheckAfterMinutes 1 -KillAfterMinutes 3 -CommandText "npm run check"Use command:watchdog for commands that may run longer than one minute.
- Do not commit
.env,data/,logs/,.pm2/, ortemp/. - Keep
ACCESS_TOKENstrong and private. - Prefer
TAILSCALE_ONLY=trueor strictTRUSTED_CIDRSfor phone access. - Do not expose this service directly to the public internet without additional authentication and network controls.
- Feishu mobile links are short-lived and should be treated as bearer tokens until they expire.
npm install
npm run devFor production-like local service management:
npm run service:start
npm run service:status
npm run service:logsnpm run check
npm run test:app-server-interactions
npm run test:feishu-interactionsMIT. See LICENSE.