Skill + CLI Interaction

When a CLI enters a botmux session, it automatically gets ~/.botmux/bin in its PATH, along with a set of ready-to-use capabilities. This is the channel through which a CLI agent can proactively interact with a Lark topic — and "terminal has output but nothing was sent to Lark" usually traces back to the model not using this channel (see FAQ · C).

Out-of-the-Box Capabilities

Inside a session the agent can call these botmux subcommands directly (session info is inferred, no id to pass):

CommandPurpose
botmux sendSend a message to the current topic (text / image / file / interactive card JSON / @mention)
botmux historyRead the current session's message history (topic groups pull within the topic; regular groups pull the whole group)
botmux quoted <message_id>Read the quoted message
botmux bots listList the bots in the current group and their open_id (for --mention)
botmux scheduleCreate, list, update, and delete scheduled tasks

These are the most-used set; the real command surface is larger (e.g. botmux ask for interactive questions, and workflow / goal / dispatch orchestration entry points) — see botmux --help and the injected Skill catalog for the full list. Handoff / orchestration are separate Skills (botmux-handoff / botmux-orchestrate), which are Skills, not executable subcommands.

The @-decision hard gate on botmux send

A botmux send must carry an @-decision, or it refuses to send: --mention <openId> (name someone), --mention-back (@ the triggerer), or --no-mention (don't @). --no-mention is mutually exclusive with the other two. Only the explicit --top-level flag (or globally disabling the gate) is exempt — ordinary topic / quote replies still have to pick one of the three. This gate ensures "the ones that should be @-ed aren't missed, and the ones that shouldn't don't spam the group."

Wrapper Mechanism

In-session commands rely on the wrapper script at ~/.botmux/bin/botmuxwritten automatically by the daemon at startup and added to the worker's PATH. The wrapper is an extremely thin exec node <this daemon's dist/cli.js> shim, so its version always matches the daemon and no separate npm i -g is needed. (Dev helpers like pnpm use:here re-point it manually with identical, idempotent content.)

Session info is inferred automatically from ancestor-process markers: when the worker launches the CLI it writes a marker keyed by the child PID (carrying sessionId / turnId), and the agent's commands walk up the process tree to the nearest marker to know which session they belong to — so the agent never passes a session id. If the process tree is broken (detached / setsid / deeply nested), it falls back to the BOTMUX_SESSION_ID environment variable.

Injection Mechanism (varies by CLI)

The channel through which routing guidance and the Skill catalog are injected varies by CLI — it's not one-size-fits-all:

  • Claude family (claude-code / seed / relay): routing / identity via --append-system-prompt; Skills via --plugin-dir (not stuffed into the system prompt).
  • genius: both routing and the Skill catalog go through --append-system-prompt; grok uses its equivalent flag --rules.
  • Most other CLIs (codex / gemini / opencode / cursor / coco / traex, etc.): under the default skillInjection=prompt mode, routing and the Skill catalog are inlined into the first prompt, consuming no system-prompt flag.

Skill catalog injection is governed by the per-bot skillInjection mode (genius/grok too): prompt (default) inlines a compact catalog into the prompt and pulls full text on demand via botmux skill show <name>; global installs the skill files into the CLI's shared skills dir (your hand-run CLI sees them too); off installs no catalog, leaving only routing guidance + botmux --help. The global/off mechanics differ from the "inline" case above.

Injected guidance is generated dynamically per the current locale, so it respects your configured language.

Why Skill + CLI Instead of MCP

Compared with an MCP-based approach, the Skill + CLI combination:

  • The CLI doesn't need an MCP handshake on startup, the core botmux send / history channels have zero MCP dependency, and it doesn't consume tool-list tokens (a gateway only starts when an adapter explicitly opts in and a plugin actually contributes MCP servers).
  • The shell / routing layer is universal — as long as a CLI can read a system prompt and run shell commands, ~/.botmux/bin/botmux + PATH work, covering Claude Code / Codex / Cursor / Gemini / OpenCode, and more.

⚠️ But the out-of-box Skill layer is not equal across every CLI: a few (e.g. Antigravity, which only recognizes SKILL.md inside plugin bundles, not a flat skills/ dir) get routing guidance only, without a Skill catalog. So "universal" holds for the shell/routing channel, and is "most" rather than "all" for the Skill catalog.