omnish
v1.6.4
Published
omnish — allowlisted inbox → your real shell (WhatsApp/Telegram; more surfaces later). No AI.
Maintainers
Readme
omnish
Website: omnish.dev
Allowlisted inbox → your real shell. No AI layer: commands run on your machine, and only identities you allow can trigger them.
Try it: omnish.dev · npm install -g omnish → Quick start (first ! command in minutes).
The OpenClaw alternative that puts developers back in control.
| WhatsApp | Telegram | |:--------:|:--------:| | | | | DM surface you already use | Same gateway pattern via bot DM |
WARNING: Remote shell access. This tool links WhatsApp and/or Telegram (and is built to add more surfaces later) to your machine and runs shell commands from allowlisted senders only. Anyone who can message from an allowed identity can run arbitrary commands as your user. Treat those identities as credentials. Do not use * wildcards on the allowlist.
Glossary: gateway, communication layer, modes
- Gateway / CLI —
omnish runon your machine: enforces allowlist and runs shell / PTY locally (security boundary for execution). - Standalone mode — messengers connect on the same host (
omnish link,omnish allow,omnish run). No hosted layer required. - Platform attached mode — link WhatsApp/Telegram once on the hosted relay; each machine runs
omnish runwithOMNISH_PLATFORM_URL+OMNISH_TOKEN(oromnish config add platform_url … platform_token …). Chat is routed to the right device; shell still runs only on that box. Docs: platform attached mode · platform reference (full API/CLI/dashboard) · communication layer model. /service“platform” — operating system (Linux, macOS, Windows), not the communication layer.
What it does
omnish link— QR login (WhatsApp → Linked devices), oromnish link --tg <bot_token>to save a Telegram bot token and setgatewayMode(telegram, orbothif WhatsApp is already linked). Seeomnish link --help.omnish run— Listen for DMs; execute commands; reply with output.omnish i— Interactive terminal with the same commands as chat (local full trust; the inbox allowlist is not applied). Run from any directory; session cwd starts at the current directory. Use/sendto <destination> <selectors> [-- caption](for examplewa,tg,*,+E164,+E164) to push files through a running gateway (seeomnish i --help). Background jobs from/bgin the REPL are only that process (not the gateway’s job list).- Sync: send
!lsor! ls(prefix configurable; default!). Each chat has its own working directory; use!cd /pathor! cd /pathto change it (saved under the data dir, e.g.~/.omnish/sessions.json). - Background:
/bgruns a long command in that chat’s cwd; optional-n myname/--namelabels the job;--notify/-Nsends a completion notification with exit code and duration. Then/jobs,/log,/tail,/killas usual. - Cowork:
/cowork//cw— scheduled or on-demand saved shell tasks with conditional notifications (always/failure/state-change), heartbeat dead-man's-switch monitoring (/cowork checkin), and logs under~/Cowork/…by default. See docs/features/cowork.md. - Webhook receiver: built-in HTTP endpoint for CI/CD notifications (GitHub Actions, GitLab CI). Enable with
webhookEnabled: true. See docs/features/webhook-receiver.md. - Watch (OS event eye): subscribe to folder changes, package installs, and named service state on Linux/macOS/Windows; notify via chat. Enable with
watchEnabled: true. See docs/features/watch.md. - Interactive PTY: drive TUIs and REPLs (
cursor-agent,claude,bash, etc.) from DMs. See Interactive sessions below. - User shortcuts: save per-chat commands under a short name (
/shortcut add myproj !cd ~/code/myproj), then run!myprojor/myprojto expand once; use$OMNISH_INPUTin the body for runtime text (!myproj <input…>)—see User shortcuts.
No AI or agent layer — direct bash -c for sync jobs; PTY uses your configured shell with -lc.
Telegram: omnish link --tg <token> (writes telegramBotToken and picks gatewayMode), then omnish allow tg:<id>; optional TELEGRAM_BOT_TOKEN overrides the file. See docs/telegram-integration-notes.md.
Multi-host cluster (optional, chat-driven): with clusterEnabled, link the same WhatsApp number to several machines (multi-device). Each allowlisted sender picks one machine to talk to with /c use <label-or-id> (or /c here to bind to the local machine); only the bound machine answers that sender's normal traffic. Two controllers can independently bind to two different machines without affecting each other. Pre-seed defaults in clusterSenderBindings. There is no shared file, no Syncthing — coordination flows through the WhatsApp chat itself via an invisible footer on each reply. See docs/features/cluster-and-chat-config.md.
Background gateway: omnish run --background (-d) and omnish stop work on Linux, macOS, and Windows (detached run + pidfile). From an allowlisted chat, /service shows status, install hints, and logs; optional /service install after /config set serviceInstallFromChat true. For login/boot, see Background gateway and start on boot and Service from chat.
Config from chat: /config show, /config get, /config set for a whitelist of config.json keys (same trust as shell). See the same doc.
Running in the background and on boot
omnish run --background(or-d) — starts detached; logs append to--log-file(default:<data>/logs/gateway.log); PID in<data>/gateway.pid.omnish stop— reads the pidfile and stops the process (SIGTERM on Unix; on Windowstaskkillis used if signaling fails).
Full steps for systemd, launchd, and Task Scheduler — docs/guides/background-and-boot.md.
| OS | Boot / auto-restart |
|----|---------------------|
| Linux | User systemd unit — contrib/omnish.service, loginctl enable-linger if needed |
| macOS | LaunchAgent — contrib/dev.omnish.gateway.plist, launchctl bootstrap / kickstart |
| Windows | Task Scheduler or import — contrib/omnish-windows-task.xml; NSSM / WinSW advanced |
Data directory
- Default:
~/.omnishfor new installs. - Legacy: if
~/.omnishdoes not exist but~/.whatslivedoes, the latter is used until you migrate. - Override:
OMNISH_HOME=/path/to/dir.
Run omnish status to see the resolved data directory and auth path.
While omnish run is active, a localhost control channel may write gateway-control.json (and a random high port on 127.0.0.1) so omnish i can request outbound file sends.
Per-chat shell cwd is in sessions.json; user shortcuts are stored in shortcuts.json (same data directory).
User shortcuts
Each chat (WhatsApp DM / Telegram DM) has its own shortcut map on disk (shortcuts.json).
| Action | Example |
|--------|--------|
| Add / overwrite | /shortcut add kidsync !cd ../../kidsync |
| List | /shortcut list or /shortcuts |
| Show | /shortcut show kidsync |
| Remove | /shortcut remove kidsync |
| Help | /shortcut help — aliases: /alias …, /aliases … (same as /shortcut …) |
Invoke: send !kidsync or /kidsync (bare name), or !kidsync <text…> / /kidsync <text…> when the body contains $OMNISH_INPUT. The saved line runs once; if it is a standalone !cd …, the session working directory updates like a normal sync cd. Shortcut bodies are not expanded again (no nesting).
Parameterized example: /shortcut add remosh /run remosh $OMNISH_INPUT then /remosh generate top 10 vid.
Names are alphanumeric plus _/-, max 32 characters; several names are reserved (e.g. help, apps, bg). See /shortcut help for the full behavior.
Install from npm
npm install -g omnish
omnish link
omnish allow +YOUR_E164
omnish runSingle phone: omnish runs on a PC or server; you link it like WhatsApp Web (one QR scan on your phone). See Quick start — One phone with WhatsApp.
Native modules (for example node-pty) may compile on install. If postinstall scripts were skipped, enable them for this package and reinstall.
Quick setup (from source)
pnpm install
# If pnpm warned about "Ignored build scripts":
pnpm approve-builds && pnpm install
pnpm omnish link
pnpm omnish allow +YOUR_E164
pnpm omnish runNative builds may be required for @whiskeysockets/baileys, sharp, protobufjs, esbuild, and node-pty. This repo sets pnpm.onlyBuiltDependencies to include node-pty; if installs still skip scripts, run pnpm approve-builds and reinstall.
npm install after pnpm install (same node_modules tree) can crash npm with Cannot read properties of null (reading 'matches'). Fix: rm -rf node_modules then pnpm install only, or pnpm run reinstall. See docs/maintainers/package-managers.md.
If link still fails with 401, run pnpm approve-builds && pnpm install, then pnpm omnish link --force to wipe the auth directory under your data dir and pair again.
denied in logs but your number is on allowFrom: WhatsApp may send your chat as a LID id (…@lid). The app resolves your real phone via remoteJidAlt / Baileys LID mapping so +E164 allowlist still matches. Use omnish run --verbose (legacy: OMNISH_VERBOSE=1 or WHATSVERBOSE=1) if you need to debug.
Phone stuck on “Logging in” then timeout: WhatsApp often sends a 515 restart right after a successful QR scan; omnish reconnects automatically. If it still times out, ensure native deps built (pnpm approve-builds && pnpm install), then try omnish link --force again.
Interactive sessions
Each chat can run several named app sessions (default up to 5 per peer, 20 globally — see appsMaxSessions / appsMaxSessionsTotal in config). At most one session is “attached”: plain DMs (no !, no /, no >) are sent to the focused session as typed text, then Enter (implemented as a short pause then \r, not text\n in one write — TUIs with bracketed-paste would otherwise never “submit”). Tune appsSubmitDelayMs (default 50) in config if needed. appsClearInput (default true) sends ^A,^K (beginning-of-line + kill line) before each outbound line and after each Enter so TUIs do not keep stale input that would concatenate with the next message; set appsClearInput to false for plain bash-only terminals if that interferes. Adjust appsClearInputSequence (comma-separated keys, see /apps key) or appsClearInputDelayMs if needed.
Precedence (per DM):
!!start/!!stop→ toggle free shell mode (plain messages run as sync shell until!!stop).- Starts with your sync prefix (default
!) → if the rest matches a shortcut (nameorname <input…>), expand once and handle the result; otherwise one-shot shell in session cwd. - Starts with
/→ built-in slash commands (/shortcut,/apps,/bg, …); if no built-in matches and/nameor/name <input…>is a shortcut, expand once; otherwise unknown/…shows help. - Starts with
>→>name textshorthand =/apps send name text(newline appended). - Else, if a session is attached and running → forward line to that app session (no reply; output streams back).
- Else, if free shell mode is on → plain text runs as a sync shell command.
- Else → short help.
Output is debounced (appsFlushMs, default 300 ms), throttled (appsMinIntervalMs, default 800 ms between sends), ANSI-stripped unless /apps raw name on, and chunked (appsMaxWaChars / appsMaxFlushBytes). When more than one session is active for the peer, lines are prefixed with [name]. Logs are always appended under <data-dir>/apps/<peer-hash-8>/<name>.log (peer hash = SHA-1 prefix of the peer key).
/apps cheat sheet
| Command | Action |
|--------|--------|
| /apps start <name> <cmd…> | Spawn app session in session cwd; auto-attaches <name>. |
| /apps attach <name> | Focus plain DMs on that running session. |
| /apps detach | Clear focus. |
| /apps list | Sessions for this chat; * marks focus. Shows attached: … or (no focus). |
| /apps info <name> / /apps get <name> | Cmd, cwd, env key count, terminal size, ring bytes, log path/size, mute/raw. |
| /apps send <name> <text> | Write text + newline (no attach). |
| >name text | Same as /apps send. |
| /apps key <name> KEY[,KEY…] | Special keys: Enter, Tab, Esc, arrows, ^C, ctrl+d, \x1b, … |
| /apps tail <name> [lines] | Last lines of log (default appsLogTailLines). |
| /apps since <name> | New log bytes since your last /apps since for that name. |
| /apps mute <name> / /apps unmute <name> | Pause / resume streaming to the chat (log still grows). |
| /apps raw <name> on\|off | Keep ANSI in streamed messages when on. |
| /apps resize <name> <cols> <rows> | Resize terminal. |
| /apps stop <name> | SIGTERM; SIGKILL after 5 s if still alive. |
| /apps kill <name> | SIGKILL immediately. |
| /apps rm <name> | Only after the process has exited; removes metadata + log file. |
To send a literal !, /, or > to the attached program, use /apps send <name> … or >name ….
Smoke test
pnpm omnish run./apps start sh bash— expect confirmation started and attached, and a bash prompt streamed back.- Plain
whoami— should print your user (viatext\n). ! pwd— sync shell runs (overrides attach)./apps start agent cursor-agent(or another TUI) — focus moves toagent; plain text goes there;>sh echo hitalks toshwithout detaching./apps list— shows*on focused session./apps detach— plain text falls back to help until you/apps attachagain./apps stop agent— exit notice[agent] exited code=…and detach if it was focused.- After exit,
/apps rm agent— removes log.
CLI
| Command | Description |
|--------|-------------|
| omnish link / link --force | Print QR; save session under <data-dir>/auth/ (--force deletes old auth first). Telegram token mode: omnish link --tg <token> (alias: --telegram). |
| omnish run | Start gateway (foreground). Background: omnish run -d [--log-file <path>]. |
| omnish stop | Stop a background gateway (omnish run -d; uses <data-dir>/gateway.pid) |
| omnish i / interactive | Chat-equivalent REPL on your terminal; omnish i --help · interactive-cli.md |
| omnish service … | Service status, logs, install/uninstall (same trust gate as /service in chat) |
| omnish logout | Delete saved WhatsApp session |
| omnish allow +1555... | Add WhatsApp number to allowlist |
| omnish allow tg:<id> | Add Telegram user id |
| omnish deny … | Remove allowlist entry |
| omnish status [--check-updates] | Data dir, auth, allowlists, jobs, cluster (if enabled); optional live npm/update check |
| omnish commands | Print chat command help on the host terminal (/help equivalent) + /config-editable keys |
| omnish security [--json] | Local security posture report (--json for scripts; non-zero exit on error findings) |
| omnish cluster [status \| use <sender> <label-or-id>] | Show cluster state or seed a sender → machine binding |
Config: <data-dir>/config.json (see config.example.json). Use omnish status for the resolved path.
Chat (allowlisted): /config (view/set many keys), /c · /pcs · /computers (chat-driven cluster — /c here to take over, /c help), /reload, /updates (/updates cached), /security (summary, tips), /service (status, instructions, logs, optional install/uninstall) — see docs/features/cluster-and-chat-config.md.
Quick file-send examples
/send ./photo.png
/send ./file1.mp4,./file2.mp4 -- Files for today
/send **/*.mp4
/sendto wa ./promo.mp4
/sendto * intro.mp4,notes.pdf -- Shared files
/sendto +15550000001,+15550000002 file1.png,file2.pngQuick meaning:
/sendsends to the current chat./sendtolets you pick recipients directly.- Selectors can be exact files (
a,b) or patterns (*.mp4,**/*.mp4).
First /sendto in 5 commands
omnish run
omnish i
!cd ~/Downloads
/sendto wa ./photo.png
/sendto * *.mp4 -- Video batchWhat to expect:
- Command 4 sends one file to all allowlisted WhatsApp numbers.
- Command 5 sends matching videos to allowlisted WhatsApp + Telegram recipients.
Documentation
Index and curated paths: docs/README.md.
| Topic | Doc |
|-------|-----|
| Vision — local first, product direction | docs/vision.md |
| Docker gateway (reference compose) | docs/guides/docker-gateway-golden-path.md |
| Interactive terminal (omnish i, /sendto multi-target) | docs/guides/interactive-cli.md |
| Configuration (config.json) | docs/guides/configuration.md |
| Browser setup UI (omnish ui) | docs/guides/ui.md |
| Cluster roster + /config from chat | docs/features/cluster-and-chat-config.md |
| Interactive sessions (/apps) | docs/features/sessions.md |
| Background jobs | docs/features/background-jobs.md |
| Webhook receiver (CI/CD notifications) | docs/features/webhook-receiver.md |
| Message routing | docs/architecture/routing.md |
| Security | docs/architecture/security.md |
| User guide | docs/guides/user-guide.md |
| Documentation search (/docs, omnish docs) | docs/features/docs-search-from-chat.md |
| System agents + /run | docs/guides/system-agents-and-run.md |
| MCP IDE spike (experimental) | contrib/mcp-spike/README.md |
| Telegram | docs/telegram-integration-notes.md |
| Send/receive files (/send selectors, /sendto destinations) | docs/files-send-receive.md |
| Troubleshooting | docs/advanced/troubleshooting.md |
| Implementation / contributors | docs/advanced/implementation.md |
| Architecture (legacy) | docs/architecture-and-implementation.md |
Troubleshooting
- Logs: stderr from
omnish run(omnish run --verbosefor Baileys; legacyOMNISH_VERBOSE=1/WHATSVERBOSE=1still works). Job logs:<data-dir>/jobs/<id>.log. App session logs:<data-dir>/apps/<8-char-sha1-prefix>/<name>.log. - If
pnpm installskipped build scripts, runpnpm approve-builds(and reinstall) so Baileys, node-pty, and other native deps compile. - WhatsApp / Baileys: see the
@whiskeysockets/baileysproject for protocol and API details.
Build (published-style)
pnpm build
node dist/index.js runRepository presentation (maintainers)
- Releases: Release and publish (GitHub + npm) — CI workflow, tagging,
NPM_TOKEN. - README and docs images use
https://omnish.dev/media/<filename>as the single source of truth so they render on npm, GitHub, and local clones without bundlingpublic/in the package. - Social preview: Repository → Settings → General → Social preview — upload an image; canonical asset:
https://omnish.dev/media/omnish_github_banner.png.
License
MIT (project code). WhatsApp is a trademark of Meta. Baileys: see @whiskeysockets/baileys license.
