Install
openclaw skills install codeflowCodeflow streams coding agent sessions (Claude Code, Codex, Gemini CLI, etc.) to Discord or Telegram in real-time. Use when invoking coding agents and wantin...
openclaw skills install codeflowLive-stream coding agent sessions to Discord or Telegram. Zero AI tokens burned.
Breaking note:
/codeflowCODEFLOW_*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:
bash {baseDir}/scripts/codeflow enforcer install --restart
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.
Run a local sanity check bundle (Python syntax compile + unit tests + bash -n):
bash {baseDir}/scripts/codeflow check
/codeflow command contract (session-scoped)When user invokes /codeflow, treat it as a control command first, then as a session-scoped declaration:
Important command-order rule:
/codeflow, /codeflow on, /codeflow status, /codeflow off, or callback_data: cfe:install is not a request for a coding task.NO_REPLY because the router already sent the user-facing control reply./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.before_prompt_build / before_tool_call blocking on top of the skill flow; it does not own /codeflow.session_status and read the current sessionKey for the active OpenClaw conversation.bash {baseDir}/scripts/codeflow control \
--session-key "<sessionKey>" \
--text "<raw user message text>"
/codeflow or /codeflow on|enable|activate/codeflow status/codeflow off|disable|deactivatecallback_data: cfe:install (or raw cfe:install)/codeflow message, always route it here first. Do not improvise a textual reply.codeflow guard activate|deactivate when neededcodeflow enforcer status --json --session-key <sessionKey>message.sendrecommendation.buttons when Telegram routing is availableInstall: / Restart: command text when buttons cannot be sentNO_REPLY.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.cfe:install, be explicit that gateway restart may interrupt or reset the current conversation/thread.Guard enforcement (hard constraint in script):
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.codeflow guard activate|deactivate|status|current) bypass the precheck.${XDG_STATE_HOME:-$HOME/.local/state}/codeflow/guard-audit.jsonl (stores commandHint only — redacted + truncated; never the full command)./codeflow in the same chat/topic.Default inference rules (do not ask unless ambiguous):
Codex session policy under /codeflow:
-w <workdir> when available (keyed by realpath(workdir)).Under /codeflow, avoid asking for workdir/platform/chat if derivable from context.
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.
exec background:true command:"cat <<'PROMPT' | {baseDir}/scripts/codeflow run -w ~/projects/myapp -- claude -p --dangerously-skip-permissions --output-format stream-json --verbose
Your task here
PROMPT"
Prompt-quoting tip (avoid shell escaping footguns):
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.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.
Public entrypoint (do not call _internal/ scripts directly):
bash {baseDir}/scripts/codeflow <command> [...]
Commands:
codeflow run [run-flags] -- <agent command> — start a relay sessioncodeflow guard activate|deactivate|status|current [run-flags] — manage/query the session-scoped guardcodeflow control --session-key <key> --text <raw_text> — deterministic /codeflow soft-mode control routercodeflow resume [run-flags] <relay_dir> — replay a previous session from stream.jsonlcodeflow review [...] <pr_url> — PR review modecodeflow parallel [...] <tasks_file> — parallel tasks modecodeflow bridge [...] — Discord gateway bridgecodeflow enforcer install|update|uninstall|status [--json] — manage/query the bundled OpenClaw enforcer plugincodeflow check — local checks (syntax + unit tests)codeflow smoke — config/prereq smoke testSee bash {baseDir}/scripts/codeflow --help for the canonical CLI.
codeflow run)| Flag | Description | Default |
|---|---|---|
-w <dir> | Working directory | Current dir |
-t <sec> | 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:
next_allowed_at = now + retry_after + 1s (strictly follows Telegram retry_after; adds +1s to avoid immediately hitting 429 again)next_allowed_atfinal > event > statestate 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 opensIf 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.
exec responsecodeflow run posts the session header and streams events to the target channel automaticallyprocess log / process poll; stop via process killCompletion 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:
When completely finished, run: openclaw system event --text "Done: <brief summary>" --mode now
process poll sessionId:<id> # Check status
process log sessionId:<id> # View recent output
process kill sessionId:<id> # Stop session
If you stream relay output into a shared channel, enable:
CODEFLOW_SAFE_MODE=trueEffects:
Write)command_execution output, raw mode output)Control how verbose channel posts are via env:
CODEFLOW_OUTPUT_MODE=minimal|balanced|verbose (default: balanced)
minimal: only warning/error/finalbalanced: key progress + warning/error/finalverbose: near-full (debug; Telegram is more likely to hit 429)Telegram compact state cards (strict snapshot overwrite):
edit the same anchor (no extra posts)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…(truncated); otherwise we do not fold/hide contentWhen -P telegram is used, Codex sessions run in compact mode by default:
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):
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)CODEFLOW_TELEGRAM_TRACK_EDIT_GROUPS=true|false: enable/disable tracking (default true)Notes:
platforms/telegram.py edit(); compact mode uses edit_single and is unaffected.edit() cannot delete/overwrite prior tail messages for already-split posts.For codex exec ..., Codeflow enforces a session policy in code (not just docs):
auto: reuse previous Codex session for the same workdir when available/new under auto: force a new session for that run--new-session: force new session--reuse-session: require previous session and force resume (error if missing)Optional env overrides:
CODEFLOW_CODEX_SESSION_MODE=auto|new|reuse (default auto)CODEFLOW_CODEX_SESSION_MAP=/tmp/dev-relay-codex-sessions.json (session map path)| Agent | Output Mode | Status |
|---|---|---|
| Claude Code | stream-json | Full support |
| Codex | --json JSONL | Full support |
| Any CLI | Raw ANSI | Basic support |
/tmp/dev-relay-sessions/<PID>.json (auto-removed on end)/tmp/dev-relay.XXXXXX/stream.jsonl (7-day auto-cleanup)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).stream.jsonl as codeflow.delivery.* (exceptions only; no message bodies/tokens/URLs)./tmp/dev-relay.XXXXXX/delivery-summary.json (single-file summary; includes rate-limit counts, drops, etc).${XDG_STATE_HOME:-$HOME/.local/state}/codeflow/guard.json (stores commandHint only — redacted + truncated)${XDG_STATE_HOME:-$HOME/.local/state}/codeflow/guard-audit.jsonl (JSONL)process submit sessionId:<id> data:"message"
{baseDir}/scripts/ (see codeflow/scripts/_internal/bin/lib.sh).curl; tokens/webhooks do not appear in child process argv (avoids ps leakage)./tmp/dev-relay-sessions/<PID>.json is written atomically (tmp + rename, best-effort fsync) and minimized (does not persist full command/context).