{"slug": "show-hn-control-claude-code-codex-pi-and-gemini-cli-from-telegram", "title": "Show HN: Control Claude Code, Codex, Pi and Gemini CLI from Telegram", "summary": "Developer Younggi Choi released cliclaw, a daemon that lets users control Claude Code, Codex, Pi, and Gemini CLI from Telegram, with per-chat agent sessions, a safety gate, and auto-detection of corporate TLS interceptors. The tool, installed via Bun or npm as @younggichoi/cliclaw, supports switching between agents, image attachments, and launchd auto-start on macOS.", "body_md": "**English** | [한국어](/choiyounggi/cliclaw/blob/main/README.ko.md)\n\nA single daemon that lets you drive four local coding CLIs (**Claude Code ·\nCodex · Pi · Gemini**) from Telegram, switching between them per chat.\n\nIt keeps an independent per-agent session for every chat, and ships a confirm gate for dangerous commands, response streaming, image-attachment handling, and auto-detection of corporate TLS interceptors (Zscaler, etc.).\n\nInstall\n\nonly the CLIs you want— missing agents are automatically dropped from the active list.\n\nThe chat UX (user messages, errors,\n\n`/help`\n\n) is currently Korean-first; the bot itself works fine either way.\n\n- macOS (Apple Silicon / Intel)\n[Bun](https://bun.sh)1.x —`curl -fsSL https://bun.sh/install | bash`\n\n**At least one** of the coding CLIs installed and logged in (the bot merely spawns authenticated child processes)- Claude Code:\n`npm install -g @anthropic-ai/claude-code`\n\n- Codex:\n`npm install -g @openai/codex`\n\n- Pi:\n`npm install -g @earendil-works/pi-coding-agent`\n\n- Gemini:\n`npm install -g @google/gemini-cli`\n\n- Claude Code:\n\n```\n# Bun (recommended)\nbun add -g @younggichoi/cliclaw\n\n# or npm\nnpm install -g @younggichoi/cliclaw\n```\n\nThe package publishes under a scoped name (\n\n`@younggichoi/cliclaw`\n\n), but the installed command is simply.`cliclaw`\n\n```\ncliclaw init\n```\n\nFive steps, guided:\n\n```\nWelcome to cliclaw setup.\n\nStep 1/5 — Telegram bot token\n  Get one from @BotFather (/newbot) on Telegram.\n  Bot token: 1234:ABC...\n  ✓ @yourbotname (id=...) verified\n\nStep 2/5 — Detect installed coding agents\n  ✓ claude  2.1.139 (Claude Code)         @ ~/.nvm/.../bin/claude\n  ✓ codex   1.0.0                          @ /opt/homebrew/bin/codex\n  ✓ pi      unknown                        @ /opt/homebrew/bin/pi\n  ✓ gemini  0.42.0                         @ ~/.nvm/.../bin/gemini\n  Default agent? [claude] (claude/codex/pi/gemini): claude\n\nStep 3/5 — Authorize your Telegram account\n  Open Telegram and send any message to @yourbotname now.\n  Waiting up to 5 minutes... press Ctrl-C to abort.\n  ✓ Received from user_id=123456789\n  Authorize this Telegram user? [Y/n] y\n\nStep 4/5 — Corporate TLS interceptor (optional)\n  $NODE_EXTRA_CA_CERTS: /path/to/Zscaler.pem\n  Apply this CA certificate to the bot's LaunchAgent environment? [Y/n] y\n\nStep 5/5 — Auto-start at login (launchd)\n  Install LaunchAgent so the bot starts automatically on login? [Y/n] y\n  ✓ Installed ~/Library/LaunchAgents/com.alice.cliclaw.plist\n  ✓ Bot started.\n\nAll set.\n  Logs:  tail -f ~/.cliclaw/logs/bot.log\n  Test:  send /status in Telegram.\n```\n\nThat's it. The bot restarts automatically after screen lock or a reboot.\n\n| Command | What it does |\n|---|---|\n`cliclaw init` |\nInteractive setup (token, agent detection, telegram-id capture, CA, launchd) |\n`cliclaw start` |\nRun the bot in the foreground (for testing) |\n`cliclaw install-launchd` |\nInstall the LaunchAgent (auto-applies `launchd.extraEnv` from config.json) |\n`cliclaw uninstall-launchd` |\nRemove the LaunchAgent |\n`cliclaw doctor` |\nCheck paths, agents, and plist status |\n`cliclaw help` |\nHelp |\n\n| Command | What it does |\n|---|---|\n`/claude` `/codex` `/pi` `/gemini` |\nSwitch this chat's active agent (uninstalled agents are hidden) |\n`/status` |\nPer-agent session status + any job in progress |\n`/health` |\nBot system status (uptime, memory, log sizes, chat/job counts) |\n`/stop` |\nCancel this chat's running job (SIGTERM → SIGKILL after 5s) |\n`/reset` |\nDiscard only the current active agent's session |\n`/reset all` |\nDiscard every agent session in this chat |\n`/safety` |\nShow safety-mode status — toggle with `/safety on` / `/safety off` |\n`/start` `/help` |\nHelp |\n| Any other text / photo | Sent as a prompt to the active agent (photos are downloaded and their path is prepended to the prompt) |\n\nSwitching agents keeps the old session intact — come back and continue. Sending\na new prompt to a chat with a running job is rejected (use `/stop`\n\nor wait).\n\nAll state is isolated under `~/.cliclaw/`\n\n:\n\n```\n~/.cliclaw/\n├── config.json              # mode 600; token, allowlist, launchd extraEnv\n├── safety.json              # persisted /safety on|off state\n├── sessions.json            # per-chat active-agent metadata\n├── sessions/                # per-chat codex / pi / gemini directories\n├── workspace/               # the agents' shared cwd (sandbox)\n│   ├── .claude/settings.json # dangerous-command hook + deny rules when safety is ON\n│   └── uploads/<chatId>/    # Telegram photo downloads\n├── logs/\n│   ├── bot.log              # token auto-masking applied\n│   ├── bot.err              # launchd stderr\n│   └── audit.jsonl          # audit log (decisions, safety state)\n└── .sock/                   # confirm-gate IPC\n```\n\nThe state directory can be moved with the `CLICLAW_HOME`\n\nenv var:\n\n```\nCLICLAW_HOME=~/my-bot cliclaw init\n```\n\nNo absolute paths in `config.json`\n\n. At startup, agents are discovered in three passes:\n\n`~/.local/bin`\n\n,`~/.claude/local`\n\n,`/usr/local/bin`\n\n,`/opt/homebrew/bin`\n\n`bin/<cmd>`\n\nof the newest node under`$NVM_DIR`\n\nor`~/.nvm`\n\n`command -v <cmd>`\n\nin a login shell (PATH with`.zshrc`\n\nloaded)\n\nUndetected agents are gracefully skipped. The bot runs fine with any subset of the four.\n\n**ON (default)**:\n\n- Dangerous Bash commands (\n`rm -rf`\n\n,`git push --force`\n\n, DROP,`kubectl delete`\n\n, AWS`delete-*`\n\n,`sudo`\n\n,`curl|sh`\n\n, ssh prd-*, …) are re-confirmed via a Telegram inline keyboard`[✅ Allow] [❌ Deny]`\n\n— no response means auto-deny. - Claude's Read tool denies sensitive files:\n`~/.ssh/**`\n\n,`~/.aws/**`\n\n,`~/.gnupg/**`\n\n,`~/.netrc`\n\n,`~/.npmrc`\n\n,`**/.env*`\n\n,`**/*.pem`\n\n,`**/id_rsa*`\n\n,`**/id_ed25519*`\n\n,`./secrets/**`\n\n. - Add your own regexes via\n`confirmGate.extraPatterns`\n\n.\n\n**OFF**: if your environment already has an external guard (`pre-bash-guard`\n\n,\nEDR, …) and the bot's confirm prompts feel redundant, turn it off with one line\nin Telegram. Deny rules are disabled together. Every IPC request is still\nrecorded in `logs/audit.jsonl`\n\nas `decision: allow, reason: safety_off`\n\n.\n\nThe state persists in `$CLICLAW_HOME/safety.json`\n\nacross restarts.\n\nConsumes `text_delta`\n\nfrom `--include-partial-messages`\n\nand live-updates via\n`editMessageText`\n\n, debounced at 1.5s. Past 3800 chars it rolls over to a new message.\n\nTelegram photos/image documents are downloaded to\n`workspace/uploads/<chatId>/<msgId>.<ext>`\n\nand the path is prepended to the prompt.\n\n**Claude**: runs with`--permission-mode bypassPermissions`\n\n— dangerous Bash is caught by the confirm gate, and sensitive files by safety-mode deny rules.**Codex**:`sandbox=workspace-write`\n\nby default. Never use`danger-full-access`\n\n.**Pi**: default mode.** Gemini**:`approvalMode=auto_edit`\n\nby default (edits auto-approved, destructive commands prompt). More autonomous`yolo`\n\nor more conservative`default`\n\n/`plan`\n\navailable.\n\nWhere Zscaler / Forticlient / Cisco Umbrella intercepts HTTPS, Node cannot\ntrust Telegram's certificate and the bot cannot run. Step 4 of `cliclaw init`\n\nauto-detects `$NODE_EXTRA_CA_CERTS`\n\nor `launchctl getenv NODE_EXTRA_CA_CERTS`\n\n,\nasks you, and persists it into `launchd.extraEnv`\n\nin `config.json`\n\n. Every later\n`install-launchd`\n\nbakes it into the plist automatically.\n\nEverything written to `logs/bot.log`\n\n/ `bot.err`\n\nis pre-redacted:\n\n- Telegram bot tokens (\n`\\d{8,}:[A-Za-z0-9_-]{30,}`\n\n) - npm tokens (\n`npm_…`\n\n) - GitHub PATs (\n`gh[pousr]_…`\n\n) - exact matches of the live\n`config.token`\n\nDefends against Time Machine backups, EDR, and shoulder surfing alike.\n\nAll user-facing messages, errors, and `/help`\n\nare in Korean (English copy PRs welcome).\n\nAnswering \"Yes\" at step 5 of `cliclaw init`\n\n:\n\n- Creates\n`~/Library/LaunchAgents/com.<username>.cliclaw.plist`\n\n(corporate CA baked in) - Loads and starts it immediately via\n`launchctl bootstrap gui/$UID <plist>`\n\n- Auto-restarts on login / boot / crash from then on\n- stdout →\n`~/.cliclaw/logs/bot.log`\n\n, stderr →`bot.err`\n\nManual management:\n\n```\n# stop (auto-restarts on next login)\nlaunchctl kill SIGTERM gui/$UID/com.<username>.cliclaw\n\n# fully disable (no auto-restart either)\ncliclaw uninstall-launchd\n\n# re-enable (auto-applies launchd.extraEnv from config.json)\ncliclaw install-launchd\n```\n\n**The bot token = a remote shell into every installed agent.** If it leaks,`/revoke`\n\nat BotFather immediately.- An empty\n`allowedUserIds`\n\nrejects all messages (fail-closed). - Keep\n`config.json`\n\nat mode`600`\n\n(init sets it automatically). - Never set\n`confirmGate.enabled: false`\n\nor switch the codex sandbox to`danger-full-access`\n\n. - Opting Gemini's\n`approvalMode`\n\ninto`yolo`\n\nauto-approves every tool — use it with full understanding. - When in doubt,\n`/safety on`\n\nre-activates the deny rules instantly.\n\nTo install without the `cliclaw init`\n\nflow:\n\n```\ngit clone https://github.com/choiyounggi/cliclaw.git\ncd cliclaw\nbun install\nmkdir -p ~/.cliclaw\ncp config.example.json ~/.cliclaw/config.json\nchmod 600 ~/.cliclaw/config.json\n# fill token and allowedUserIds in config.json, then\nbun run bot.ts\nbun run test\n```\n\n- Dangerous patterns are regex-based — 100% classification is impossible; you own the policy.\n- No body-text streaming for Codex / Pi / Gemini (no structured events, or not integrated).\n- Gemini's dangerous commands rely solely on its own\n`approvalMode`\n\n(bash-confirm IPC not integrated). - The hook holds the IPC while waiting for the user's decision.\n- No voice/file attachments (photos only).\n- Concurrent messages in the same chat are rejected (\n`/stop`\n\nor wait). - macOS only.\n\nPer-version changes live on [GitHub Releases](https://github.com/choiyounggi/cliclaw/releases).\n\nPublishing a new version:\n\n```\n# 1) bump the version (auto-creates commit + tag)\nnpm version patch          # or minor / major\n\n# 2) push commit + tag\ngit push --follow-tags\n```\n\nThen in the GitHub web UI: \"Draft a new release\" → pick the tag → Publish\nrelease. `.github/workflows/publish.yml`\n\nruns automatically through\n`npm publish --access public`\n\n. The workflow first verifies the release tag\nmatches the `package.json`\n\nversion and fails without publishing on a mismatch.\n\n**One-time prerequisite**: repo Settings → Secrets and variables → Actions →\nregister **NPM_TOKEN** with an npm token capable of 2FA bypass.\n\n[https://www.npmjs.com/settings/younggichoi/tokens/new](https://www.npmjs.com/settings/younggichoi/tokens/new)- Issue a Granular Access Token or a Classic\n**Automation** token (with 2FA bypass) - Add the\n`npm_…`\n\ntoken as the GitHub Actions secret`NPM_TOKEN`\n\n**Hardening option**: switch to npm Trusted Publishing (OIDC) and no token is needed at all.\n\n- At\n[https://www.npmjs.com/package/@younggichoi/cliclaw/access](https://www.npmjs.com/package/@younggichoi/cliclaw/access), add Trusted Publisher → GitHub Actions (workflow filename:`publish.yml`\n\n) - In\n`.github/workflows/publish.yml`\n\n, add`permissions: id-token: write`\n\n, remove`NODE_AUTH_TOKEN`\n\n, add the`--provenance`\n\nflag - Delete the old NPM_TOKEN secret\n\n- Code contributions:\n[CONTRIBUTING.md](/choiyounggi/cliclaw/blob/main/CONTRIBUTING.md) - Dev flow & directory structure:\n[DEVELOPMENT.md](/choiyounggi/cliclaw/blob/main/DEVELOPMENT.md) - Security policy, threat model, vulnerability reports:\n[SECURITY.md](/choiyounggi/cliclaw/blob/main/SECURITY.md)\n\nMIT. See `LICENSE`\n\n.", "url": "https://wpnews.pro/news/show-hn-control-claude-code-codex-pi-and-gemini-cli-from-telegram", "canonical_source": "https://github.com/choiyounggi/cliclaw", "published_at": "2026-08-14 05:07:01+00:00", "updated_at": "2026-08-14 05:41:15.219635+00:00", "lang": "en", "topics": ["developer-tools", "ai-tools", "ai-agents"], "entities": ["Younggi Choi", "cliclaw", "Claude Code", "Codex", "Pi", "Gemini CLI", "Telegram", "Bun"], "alternates": {"html": "https://wpnews.pro/news/show-hn-control-claude-code-codex-pi-and-gemini-cli-from-telegram", "markdown": "https://wpnews.pro/news/show-hn-control-claude-code-codex-pi-and-gemini-cli-from-telegram.md", "text": "https://wpnews.pro/news/show-hn-control-claude-code-codex-pi-and-gemini-cli-from-telegram.txt", "jsonld": "https://wpnews.pro/news/show-hn-control-claude-code-codex-pi-and-gemini-cli-from-telegram.jsonld"}}