Codeflow
Live-stream coding agent sessions to Discord or Telegram. Zero AI tokens burned.
Breaking note:
- - Command name: INLINECODE0
- Env var prefix: INLINECODE1
Setup
First-time setup: see references/setup.md for webhook creation, unbuffer install, bot token, and smoke test.
For hard thread-scoped enforcement (skill-owned /codeflow + plugin tool blocking), install the bundled enforcer plugin once on the host:
CODEBLOCK0
If the plugin is missing, /codeflow still works in soft mode. The button/no-button behavior must be owned by the deterministic router script, not by free-form assistant prose.
Developer Checks (optional)
Run a local sanity check bundle (Python syntax compile + unit tests + bash -n):
CODEBLOCK1
/codeflow command contract (session-scoped)
When user invokes /codeflow, treat it as a control command first, then as a session-scoped declaration:
- 1. For the current OpenClaw session, all coding, development, or review tasks (code/architecture/security/product review) — including any direct Codex or Claude Code invocations — must be executed via Codeflow relay + local Codex/Claude Code (not direct edits unless explicitly requested).
- Follow Codeflow output conventions (including compact Telegram behavior when applicable).
- If user asks for direct non-code tasks, handle normally; this contract applies to coding, development, and review tasks.
- The contract lasts for the current session context. If user resets/new session, require re-invocation.
Important command-order rule:
- - A bare control message such as
/codeflow, /codeflow on, /codeflow status, /codeflow off, or callback_data: cfe:install is not a request for a coding task. - For these control messages, do not send a generic acknowledgement like “ready, what should I do next?”.
- First execute the deterministic control router below.
- If the router succeeds, end with
NO_REPLY because the router already sent the user-facing control reply. - Only after that should later coding tasks in the same session be executed under the Codeflow contract.
- If the same inbound message includes both the
/codeflow command and an actual coding task, run the control router first, then continue with the remaining task text.
Soft fallback contract:
- -
/codeflow is always owned by the skill. That is the public entrypoint and the soft fallback path. - The bundled enforcer plugin is optional. When installed, it adds hard
before_prompt_build / before_tool_call blocking on top of the skill flow; it does not own /codeflow. - Step 0) Call
session_status and read the current sessionKey for the active OpenClaw conversation. - Step 1) Always run the deterministic control script:
CODEBLOCK2
- - The script owns these cases:
-
/codeflow or
/codeflow on|enable|activate
-
/codeflow status
-
/codeflow off|disable|deactivate
-
callback_data: cfe:install (or raw
cfe:install)
- - For a bare
/codeflow message, always route it here first. Do not improvise a textual reply. - The script performs the real work itself:
- runs
codeflow guard activate|deactivate when needed
- runs
codeflow enforcer status --json --session-key <sessionKey>
- sends the final message itself via Gateway
message.send
- includes
recommendation.buttons when Telegram routing is available
- falls back to plain
Install: /
Restart: command text when buttons cannot be sent
- - Normal path: the script already sent the user-facing reply, so end the turn with
NO_REPLY. - Fallback path: if the script exits with code
3 and stdout starts with NEED_LLM_ROUTE, parse the JSON payload on the next line ({message, buttons}) and send that yourself. If your current channel/tooling cannot attach buttons, keep the plain text exactly as provided. - Installer note: when handling
cfe:install, be explicit that gateway restart may interrupt or reset the current conversation/thread.
Guard enforcement (hard constraint in script):
- - All execution modes that can post/run work (
run, resume, review, parallel) are guard-protected by default. review and parallel must precheck the guard before they clone repos, create worktrees, or post start summaries. - Guard management commands (
codeflow guard activate|deactivate|status|current) bypass the precheck. - Guard is bound to chat/topic context (and session key when available).
- Every allow/deny decision is appended to
${XDG_STATE_HOME:-$HOME/.local/state}/codeflow/guard-audit.jsonl (stores commandHint only — redacted + truncated; never the full command). - If blocked, instruct user to re-run
/codeflow in the same chat/topic.
Default inference rules (do not ask unless ambiguous):
- - Task content: ask user for this when missing.
- Workdir: infer from recent chat/context/task history (not blindly current workspace). If unclear, ask user to re-declare workdir.
- Platform: infer from current channel (Telegram/Discord).
- Target chat/thread: infer from inbound metadata (current chat/thread).
Codex session policy under /codeflow:
- - Reuse the prior Codex session associated with the same
-w <workdir> when available (keyed by realpath(workdir)). - If no prior session is found, create a new session when the task is dispatched.
- Only force new session when user explicitly requests it.
Under /codeflow, avoid asking for workdir/platform/chat if derivable from context.
Invocation
Launch with exec background:true. Background exec sessions survive agent turns. Exit notifications (e.g. notifyOnExit) are provided by the host runtime (OpenClaw), not by Codeflow itself.
CODEBLOCK3
Prompt-quoting tip (avoid shell escaping footguns):
- - For Codex,
codex exec (and codex exec resume) reads the prompt from stdin when PROMPT is - (or omitted in exec). For multi-line prompts or prompts containing shell metacharacters (e.g. backticks), prefer stdin + a quoted heredoc. - For Claude Code,
claude -p also supports reading the prompt from stdin; prefer stdin for the same reasons.
Note the session ID from the response — use it to monitor via process.
CLI (stable)
Public entrypoint (do not call _internal/ scripts directly):
CODEBLOCK4
Commands:
- -
codeflow run [run-flags] -- <agent command> — start a relay session - INLINECODE62 — manage/query the session-scoped guard
- INLINECODE63 — deterministic
/codeflow soft-mode control router - INLINECODE65 — replay a previous session from INLINECODE66
- INLINECODE67 — PR review mode
- INLINECODE68 — parallel tasks mode
- INLINECODE69 — Discord gateway bridge
- INLINECODE70 — manage/query the bundled OpenClaw enforcer plugin
- INLINECODE71 — local checks (syntax + unit tests)
- INLINECODE72 — config/prereq smoke test
See bash {baseDir}/scripts/codeflow --help for the canonical CLI.
Run flags (codeflow run)
| Flag | Description | Default |
|---|
| INLINECODE75 | Working directory | Current dir |
| INLINECODE76 |
Timeout | 1800 |
|
-h <sec> | Hang threshold | 120 |
|
-n <name> | Agent display name | Auto-detected |
|
-P <platform> |
discord,
telegram,
auto (inferred) | discord |
|
--thread | Post into a Discord thread | Off |
|
--tg-chat <id> | Telegram chat id (when
-P telegram) | — |
|
--tg-thread <id> | Telegram thread/topic id (optional) | — |
|
--skip-reads | Hide Read tool events | Off |
|
--new-session | For Codex exec: force a new Codex session | auto policy |
|
--reuse-session | For Codex exec: require and reuse previous session | auto policy |
|
--prompt-stdin | Enforce prompt via stdin for supported headless agents (Codex exec / Claude
-p) | Auto (OpenClaw → on) |
|
--prompt-argv | Allow legacy argv prompt for supported headless agents | Auto (non-OpenClaw → on) |
Prompt mode can also be set via env: CODEFLOW_PROMPT_MODE=auto|argv|stdin (default: auto).
Rate limiting note (Telegram hardening): parse-stream now routes all delivery through an in-process delivery governor with strict 429 handling:
- - Telegram 429 backoff:
next_allowed_at = now + retry_after + 1s (strictly follows Telegram retry_after; adds +1s to avoid immediately hitting 429 again) - do not send any request before INLINECODE97
- queue priority:
final > event > INLINECODE100 - compact
state cards (thinking/cmd) are strict snapshot overwrite (latest-wins); during 429 windows updates are merged in memory and only the latest snapshot is applied once the window opens
If you still need to reduce output volume, use CODEFLOW_OUTPUT_MODE (see below) plus existing knobs (--skip-reads, CODEFLOW_SAFE_MODE=true, CODEFLOW_COMPACT).
For PR review, parallel tasks, Discord bridge, and Codex structured output: see references/advanced-modes.md.
Agent Launch Checklist
- 1. Start background session → note session ID from the
exec response - INLINECODE107 posts the session header and streams events to the target channel automatically
- Monitor via
process log / process poll; stop via INLINECODE110
Completion Detection
Completion notifications are runtime-dependent (OpenClaw). Codeflow itself simply exits when the inner agent command exits.
Backup: Append this to the inner agent's prompt for an additional signal:
CODEBLOCK5
Monitoring
CODEBLOCK6
Safe mode (optional)
If you stream relay output into a shared channel, enable:
Effects:
- - Suppress file-content previews (Claude
Write) - Suppress command output bodies (Claude Bash output, Codex
command_execution output, raw mode output) - Apply stricter redaction to high-risk fields
Output mode
Control how verbose channel posts are via env:
- -
CODEFLOW_OUTPUT_MODE=minimal|balanced|verbose (default: balanced)
-
minimal: only
warning/error/final
-
balanced: key progress +
warning/error/final
-
verbose: near-full (debug; Telegram is more likely to hit 429)
Telegram compact state cards (strict snapshot overwrite):
- - thinking/cmd cards always
edit the same anchor (no extra posts) - each
edit replaces the full snapshot (no accumulated log); during 429 windows updates are merged in memory (latest-wins) and only the latest snapshot is applied once the window opens - only when the message exceeds platform limits do we truncate/compress and mark
…(truncated); otherwise we do not fold/hide content
Telegram anti-spam mode (default)
When -P telegram is used, Codex sessions run in compact mode by default:
- - per turn, one rolling "thinking" message (edited in place)
- per turn, one rolling "commands/results" message (edited in place)
- one separate turn-complete output message (full text; paginated if oversized)
Next turn starts a fresh pair of rolling messages.
Override with env:
- -
CODEFLOW_COMPACT=true|false (default auto, where Telegram => true)
Telegram 429 / anchor stability (compact mode):
- - edit failures do not "post a new anchor immediately" (no anchor explosion); state cards preserve single-anchor edit semantics
- on 429, Codeflow sleeps for
retry_after + 1s (not a fixed 10s); when the window opens, it flushes by priority (final > event > state)
Telegram adapter memory guard (oversized message edit groups):
- -
CODEFLOW_TELEGRAM_EDIT_GROUPS_MAX=<n>: max tracked groups (LRU, default 64; set 0 to disable tracking) - INLINECODE131 : enable/disable tracking (default
true)
Notes:
- - This only affects multi-message editing via
platforms/telegram.py edit(); compact mode uses edit_single and is unaffected. - Disabling tracking means
edit() cannot delete/overwrite prior tail messages for already-split posts.
Codex session reuse policy (hard workflow constraint)
For codex exec ..., Codeflow enforces a session policy in code (not just docs):
- - default
auto: reuse previous Codex session for the same workdir when available - if prompt contains
/new under auto: force a new session for that run - INLINECODE141 : force new session
- INLINECODE142 : require previous session and force resume (error if missing)
Optional env overrides:
- -
CODEFLOW_CODEX_SESSION_MODE=auto|new|reuse (default auto) - INLINECODE145 (session map path)
Agent Support
| Agent | Output Mode | Status |
|---|
| Claude Code | stream-json | Full support |
| Codex |
--json JSONL | Full support |
| Any CLI | Raw ANSI | Basic support |
Session Tracking
- - Active sessions:
/tmp/dev-relay-sessions/<PID>.json (auto-removed on end) - Event logs:
/tmp/dev-relay.XXXXXX/stream.jsonl (7-day auto-cleanup) - Stream log policy:
CODEFLOW_STREAM_LOG=full|redacted|off (default: full; if CODEFLOW_SAFE_MODE=true and CODEFLOW_STREAM_LOG is unset, default becomes redacted). off writes minimal metadata only (resume/debug is limited). - Delivery anomaly events: appended into
stream.jsonl as codeflow.delivery.* (exceptions only; no message bodies/tokens/URLs). - Delivery stats (local):
/tmp/dev-relay.XXXXXX/delivery-summary.json (single-file summary; includes rate-limit counts, drops, etc). - Guard state:
${XDG_STATE_HOME:-$HOME/.local/state}/codeflow/guard.json (stores commandHint only — redacted + truncated) - Guard audit log:
${XDG_STATE_HOME:-$HOME/.local/state}/codeflow/guard-audit.jsonl (JSONL) - Interactive input: INLINECODE160
- If the XDG state dir is not writable, guard/state/audit fall back to dotfiles under
{baseDir}/scripts/ (see
codeflow/scripts/_internal/bin/lib.sh).
- - Telegram/Discord delivery no longer spawns
curl; tokens/webhooks do not appear in child process argv (avoids ps leakage). - INLINECODE165 is written atomically (tmp + rename, best-effort fsync) and minimized (does not persist full command/context).
Reference Docs
Codeflow
将编码助手会话实时直播到 Discord 或 Telegram。零 AI Token 消耗。
重要提示:
- - 命令名称:/codeflow
- 环境变量前缀:CODEFLOW_*
设置
首次设置:请参阅 references/setup.md 了解 Webhook 创建、unbuffer 安装、机器人令牌和冒烟测试。
如需强制执行严格的线程范围限制(技能拥有的 /codeflow + 插件工具拦截),请在主机上安装一次捆绑的强制插件:
bash
bash {baseDir}/scripts/codeflow enforcer install --restart
如果缺少该插件,/codeflow 仍可在软模式下工作。按钮/无按钮行为必须由确定性路由器脚本控制,而非自由形式的助手散文。
开发者检查(可选)
运行本地健全性检查包(Python 语法编译 + 单元测试 + bash -n):
bash
bash {baseDir}/scripts/codeflow check
/codeflow 命令契约(会话范围)
当用户调用 /codeflow 时,将其视为控制命令优先,然后作为会话范围声明:
- 1. 对于当前 OpenClaw 会话,所有编码、开发或审查任务(代码/架构/安全/产品审查)——包括任何直接的 Codex 或 Claude Code 调用——必须通过 Codeflow 中继 + 本地 Codex/Claude Code 执行(除非明确要求,否则不直接编辑)。
- 遵循 Codeflow 输出约定(包括适用时的紧凑 Telegram 行为)。
- 如果用户要求直接的非编码任务,则正常处理;此契约适用于编码、开发和审查任务。
- 该契约在当前会话上下文中有效。如果用户重置/新建会话,则需要重新调用。
重要命令顺序规则:
- - 裸控制消息如 /codeflow、/codeflow on、/codeflow status、/codeflow off 或 callbackdata: cfe:install 不是编码任务请求。
- 对于这些控制消息,不要发送通用确认消息,如“已就绪,接下来需要做什么?”。
- 首先执行下面的确定性控制路由器。
- 如果路由器成功,则以 NOREPLY 结束,因为路由器已发送面向用户的控制回复。
- 只有在此之后,同一会话中的后续编码任务才应在 Codeflow 契约下执行。
- 如果同一条入站消息同时包含 /codeflow 命令和实际编码任务,则先运行控制路由器,然后继续处理剩余的任务文本。
软回退契约:
- - /codeflow 始终由技能拥有。这是公共入口点和软回退路径。
- 捆绑的强制插件是可选的。安装后,它会在技能流程之上添加硬性的 beforepromptbuild / beforetoolcall 拦截;它不拥有 /codeflow。
- 步骤 0) 调用 session_status 并读取当前活动 OpenClaw 对话的 sessionKey。
- 步骤 1) 始终运行确定性控制脚本:
bash
bash {baseDir}/scripts/codeflow control \
--session-key \
--text <原始用户消息文本>
- /codeflow 或 /codeflow on|enable|activate
- /codeflow status
- /codeflow off|disable|deactivate
- callback_data: cfe:install(或原始 cfe:install)
- - 对于裸 /codeflow 消息,始终先路由到此。不要即兴编写文本回复。
- 脚本自行执行实际工作:
- 需要时运行 codeflow guard activate|deactivate
- 运行 codeflow enforcer status --json --session-key
- 通过 Gateway message.send 自行发送最终消息
- 当 Telegram 路由可用时包含 recommendation.buttons
- 当无法发送按钮时,回退到纯文本 Install: / Restart: 命令文本
- - 正常路径:脚本已发送面向用户的回复,因此以 NOREPLY 结束本轮。
- 回退路径:如果脚本以代码 3 退出且 stdout 以 NEEDLLM_ROUTE 开头,则解析下一行的 JSON 负载({message, buttons})并自行发送。如果您当前的频道/工具无法附加按钮,请完全按原样保留纯文本。
- 安装程序说明:处理 cfe:install 时,明确说明网关重启可能会中断或重置当前对话/线程。
守卫强制(脚本中的硬约束):
- - 所有可以发布/运行工作的执行模式(run、resume、review、parallel)默认受守卫保护。review 和 parallel 在克隆仓库、创建工作树或发布开始摘要之前必须预先检查守卫。
- 守卫管理命令(codeflow guard activate|deactivate|status|current)绕过预先检查。
- 守卫绑定到聊天/主题上下文(以及可用的会话密钥)。
- 每个允许/拒绝决策都追加到 ${XDGSTATEHOME:-$HOME/.local/state}/codeflow/guard-audit.jsonl(仅存储 commandHint——经过编辑和截断;从不存储完整命令)。
- 如果被阻止,指示用户在同一个聊天/主题中重新运行 /codeflow。
默认推断规则(除非不明确,否则不要询问):
- - 任务内容:缺失时向用户询问。
- 工作目录:从最近的聊天/上下文/任务历史推断(不是盲目使用当前工作空间)。如果不明确,要求用户重新声明工作目录。
- 平台:从当前频道推断(Telegram/Discord)。
- 目标聊天/线程:从入站元数据推断(当前聊天/线程)。
/codeflow 下的 Codex 会话策略:
- - 当可用时,重用与相同 -w 关联的先前 Codex 会话(以 realpath(workdir) 为键)。
- 如果未找到先前会话,则在任务分发时创建新会话。
- 仅在用户明确要求时强制创建新会话。
在 /codeflow 下,如果可以从上下文推导,避免询问工作目录/平台/聊天。
调用
使用 exec background:true 启动。后台执行会话在助手轮次之间持续存在。退出通知(例如 notifyOnExit)由主机运行时(OpenClaw)提供,而非 Codeflow 本身。
bash
exec background:true command:cat <
您的任务在此
PROMPT
提示引用技巧(避免 shell 转义陷阱):
- - 对于 Codex,codex exec(和 codex exec resume)在 PROMPT 为 -(或在 exec 中省略)时从 stdin 读取提示。对于多行提示或包含 shell 元字符(如反引号)的提示,优先使用 stdin 加引号的 heredoc。
- 对于 Claude Code,claude -p 也支持从 stdin 读取提示;出于相同原因优先使用 stdin。
注意响应中的会话 ID——使用它通过 process 进行监控。
CLI(稳定版)
公共入口点(不要直接调用 _internal/ 脚本):
bash
bash {baseDir}/scripts/codeflow [...]
命令:
- - codeflow run [run-flags] -- — 启动中继会话
- codeflow guard activate|deactivate|status|current [run-flags] — 管理/查询会话范围的守卫
- codeflow control --session-key --text text> — 确定性 /codeflow 软模式控制路由器
- codeflow resume [run-flags] dir> — 从 stream.jsonl 重放先前会话
- codeflow review [...] url> — PR 审查模式
- codeflow parallel [...] file> — 并行任务模式
- codeflow bridge [...] — Discord 网关桥接
- codeflow enforcer install|update|uninstall|status [--json] — 管理/查询捆绑的 OpenClaw 强制插件
- codeflow check — 本地检查(语法 + 单元测试)
- codeflow smoke — 配置/前置条件冒烟测试
参见 bash {baseDir}/scripts/codeflow --help 获取规范 CLI。
运行标志(codeflow run)
| 标志 | 描述 | 默认值 |
|---|
| -w <dir> | 工作目录 | 当前目录 |
| -t <sec> |
超时时间 | 1800 |
| -h | 挂起阈值 | 120 |
| -n