关于 gateway
gateway 是用于运维常驻网关守护进程的技能,供负责 joelclaw 通知与通信层的操作者使用。它要求通过 joelclaw gateway CLI 进行诊断、恢复和通道管理,并提供会话压力及通道健康信息。
主要功能
- 01检查状态、依赖与运行健康
- 02重启或启用网关服务
- 03管理通信通道启用状态
- 04诊断会话压力与通道故障
- 05跟踪操作确认和超时
适用场景
- 01排查网关或通信通道异常
- 02恢复被停用的守护进程
- 03检查会话压力和维护状态
- 04确认操作是否完成或超时
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ joelhooks/ joelclaw --skill gateway安装后在 Claude Code 中输入/gateway确认已加载。
附带文件agents/openai.yamlassets/small-logo.svg
详细介绍
网关运维
网关守护进程是始终运行的 pi 会话,负责接收 Inngest 函数、Telegram 和 Webhook 发来的事件。它是系统的通知与通信层。
规则:始终使用 joelclaw gateway CLI。绝不要直接使用 launchctl、curl 或 grep 日志文件。
CLI 命令
joelclaw gateway doctor # PASS/FAIL process, live source tree, Redis, adapter, and poller
joelclaw gateway doctor --live # Full notify path; requires Telegram platformMessageId
joelclaw gateway status # Daemon availability, runtime mode, session pressure, Redis health
joelclaw gateway restart # Roll daemon, then print the doctor summary
joelclaw gateway enable # Re-enable launch agent + start daemon
joelclaw gateway test # Push test event, verify delivery (Redis bridge path)
joelclaw gateway push --type <type> [--payload JSON] # Push an event to all sessions
joelclaw gateway events # Peek at pending events per session
joelclaw gateway drain # Clear all event queues
joelclaw gateway stream # NDJSON stream of all gateway events (ADR-0058)
joelclaw gateway channel {list|status|enable|disable} # Enable/disable runtime channels
joelclaw gateway behavior {add|list|promote|remove|apply|stats} # ADR-0211 behavior control plane
joelclaw gateway restart 是标准重启方式。它会终止进程、清理 Redis 状态、在 launchd 禁用了 com.joel.gateway 时重新启用它、等待 launchd 重新启动进程、记录运维人员重启标记,并输出 doctor 摘要。joelclaw gateway enable 是 launchd 配置漂移导致服务被禁用时的直接恢复途径。绝不要直接使用 launchctl bootout/bootstrap。
运行中的守护进程会从主 joelclaw 工作树执行源代码。绝不要在该目录中保留会触及网关的 WIP。请使用单独的 Git 工作树,以免守护进程崩溃后重新启动时运行未完成编辑的代码。gateway doctor 会在守护进程正在运行且网关运行时源代码存在未提交更改时明确报错。其 --live 验证要求提供真实的 Telegram platformMessageId;没有该 ID 的 confirmed 遥测数据不能作为已送达的证明。
启用/禁用渠道
使用 CLI。除非 CLI 出现故障,否则不要手动编辑 ~/.joelclaw/scripts/gateway-start.sh。
joelclaw gateway channel list
joelclaw gateway channel disable discord --restart
joelclaw gateway channel enable discord --restart
joelclaw gateway channel status discord
CLI 会清空或还原 ~/.joelclaw/scripts/gateway-start.sh 中的渠道环境变量赋值,在更改前写入 /tmp/joelclaw/gateway-start.sh.* 备份,并可在指定 --restart 时重启网关。由于 Telegram 是主要运维渠道,禁用它需要使用 --force。临时禁用时不要撤销或删除已存储的密钥。
预期的 Discord 禁用状态:组件为 disabled;渠道为 configured:false、started:false、ready:false、botUserId:null;健康状态条目为 status:"disabled"。
快速排查
先运行 joelclaw gateway doctor、status 和受支持的诊断命令。探测依赖项之前,先确认配置的所有者。本地缺少 Colima 或 Kubernetes 并不能证明网关依赖项已宕机。
沿着第一个相关故障追查其原因。继续排查相互独立的问题,并执行已请求的修复。队列年龄本身不代表卡住:执行有针对性的重启前,请检查活动进度、配置的超时时间和进程证据。
doctor --live 和 gateway test 会发送真实流量。只有在获得目的地和内容相关授权的范围内才能使用它们。单纯诊断并不构成发送出站测试消息的授权。队列确认不等于送达证明。
Redis 降级模式(ADR-0214)
joelclaw gateway status 现在会区分:
mode: normal— Redis 桥接正常mode: redis_degraded— 守护进程/渠道/会话可用,但基于 Redis 的功能处于降级状态
当 mode=redis_degraded 时:
- 直接与真人对话仍可能正常工作
- 基于 Redis 的命令/检查只能部分信任
joelclaw gateway test会验证 Redis 桥接路径,因此joelclaw gateway diagnose按设计会跳过这一层- 使用
joelclaw gateway diagnose查看降级功能列表和会话压力字段
除非进程/会话健康状况也出现故障,否则不要将 redis_degraded 报告为“网关宕机”。
Gateway 上下文刷新范围(ADR-0204)
只有在限定范围内进行时,Gateway 滚动上下文刷新才有用。
硬性规则:
- 不要将自动摘要、Gateway 事件封装、恢复摘要或简短确认视为回忆种子
- 如果没有真实的对话主题,就跳过刷新,而不是查询通用全局记忆
原因:
- 错误的隐藏
context-refresh注入会污染正在运行的 Gateway 会话,即使joelclaw gateway status仍报告健康 - 这曾表现为无关的语音/livekit 备注渗入 Gateway 记录
如果 Joel 觉得 Gateway 会话“糟透了”,而健康检查却显示正常,请先遵循范围绑定的会话证据契约,再检查 Gateway 记录中的隐藏 context-refresh/gateway-recovery/memory-recall 消息,然后再相信 CLI 摘要。
会话压力可见性(ADR-0218 第 3 级切片)
现在,joelclaw gateway status/joelclaw gateway diagnose 会显示具体的会话压力信息,而不只是粗略的健康状态:
- 上下文使用率 % + 下一步操作
- 下一阈值摘要(
compact at 65% .../rotate at 75% .../rotate immediately) - 距上次压缩的时间 + 会话时长
- 线程数(
active/warm/total) - 回退状态 + 激活次数 + 连续提示词失败次数
- 压力原因(
context_usage、context_ceiling、compaction_gap、session_age) - 上次告警的健康状态/时间 + 冷却状态
守护进程会在 daemon.session-pressure 下发出 OTEL 数据(session_pressure.alert.suppressed|failed)。会话压力状态不会触发 Telegram 页面告警;轮换/压缩压力会保留在状态/诊断/OTEL 中,因为这是 Gateway 维护工作,而非 Joel 的操作。
对于基于时间的压力,空闲维护会自主进行:
- 即使当前没有活动轮次,watchdog 也会评估空闲会话压力
- 超期的压缩间隔会触发自主压缩,而不是等待下一次人工/事件轮次
- watchdog 路径也可能触发基于会话时长的轮换;由于 Pi 移除了
AgentSession.newSession(),Gateway 会写入/tmp/joelclaw/gateway.force-new-session.json并正常退出,让 launchd 重启并进入全新的SessionManager,随后在下一次入站轮次前将压缩摘要作为隐藏上下文注入 - 这些由 watchdog 触发的运行会发出与轮次绑定维护相同的
daemon.maintenance.started|completed|failed遥测数据
Tripwire 调查器
每五分钟运行一次的 Gateway 心跳 tripwire 会启动一个可见的调查器,而不是重复发送原生告警。
infra/gateway-tripwire.sh会检测missing和stale心跳状态。infra/gateway-alert-investigator.sh会在默认的 Aqua Herdr 会话中启动或恢复一个事件。- 该事件会验证已配置的 DGX 端点,然后使用
dgx-glm/glm-5.3-flash:high和常规工具启动 Pi。 - 重复出现的异常检查会复用同一工作区。失效的 Agent 会在原处重启。模型或 Herdr 启动失败时,会在五分钟后重试。
- 只有当工作区达到
review ready状态,且同一个 Agent 接受根因回执提示词后,恢复状态才会解除待处理。 - 只有在 Herdr 或调查器无法启动时,才会使用原生通知作为回退方案。
调查器遵循此技能。它必须使用 joelclaw gateway 进行生命周期变更,并且不得启动其他通信传输方式。持久化设计细节位于 .brain/resources/gateway-herdr-alert-investigator.svx。
可中断性与取代(ADR-0196 / ADR-0218 第 4 级切片)
对于通过 Telegram、Discord、iMessage 和 Slack 调用路径发起的直接人工对话轮次,现在以最新消息为准。
运行时约定:
- 新的人工对话轮次会先经过一个较短的
1.5s批处理窗口,然后再分发 - 按来源进行批处理,因此快速连续发送的后续消息会合并为一个排队的提示词
- 如果该来源已有活动任务,网关会立即取代当前任务,而不是等待计时器
- 丢弃该来源已过时的排队提示词
- 持久化队列重放不得自行丢弃最新的人工消息;仅当确实存在来自同一来源的更新消息时,才会触发取代
- 守护进程会对过时轮次请求
session.abort() - 抑制过时的响应文本,而不是延迟发送
joelclaw gateway status会公开supersession和supersession.batchingjoelclaw gateway diagnose会新增interruptibility层,其中包含取代和批处理详情
被动情报 / 后台事件路由不走此路径。
操作者确认 / 超时追踪(ADR-0218 第 5 级切片)
Telegram 操作者操作现在会获得追踪 ID,并进行明确的生命周期追踪。
当前覆盖的路径:
cmd:*命令菜单回调worktree:*回调pitch:*ADR 提案回调- 默认 Telegram 回调操作和外部回调路由移交
- 通过命令处理程序注册的直接 Telegram 斜杠命令
- 原生 Telegram
/stop、/esc和/kill命令
网关现在会为这些路径追踪 kind=callback|command 以及 ack/dispatched/completed/failed/timed_out 状态,在 joelclaw gateway status 中公开规范的 operatorTracing(保留 callbackTracing 作为兼容别名),并在 joelclaw gateway diagnose 中新增 operator-tracing 层。
排队的 Telegram Agent 命令现在会在下游网关执行期间保留其追踪 ID,在真实轮次完成路径上标记完成,并在提示词错误 / 助手错误 / 被取代时标记失败,而不是在入队时就错误地报告完成。由 Agent 提供支持的命令追踪,其超时时间窗口比简单的回调确认路径更长。
外部回调路由现在也支持 Redis 追踪结果移交:网关会让已路由的回调保持活动状态,下游使用方可以使用相同的 traceId 发布 completed / failed,并且代码库内的 Restate Telegram 路由已接入此机制,可在下游实际完成处理后关闭追踪。
尚待解决:任何未采用此移交机制的外部回调使用方,仍会超时并被视为未追踪工作。
通道运行时约定(ADR-0218 第 6 级切片)
joelclaw gateway status 现在会公开规范的 channels 信息,以及 Telegram、Discord、iMessage 和 Slack 的汇总 channelHealth。joelclaw gateway diagnose 会新增 channel-health 层,以便在全面中断之前发现主用 / 被动 / 回退以及半失效的通道状态。
当前第 6 级行为还会由守护进程立即发送降级 / 恢复告警,在 daemon.channel-health 下发出 OTEL 信号,遵循 joelclaw gateway known-issues 的静音状态,避免已知不稳定的通道反复误报,并按通道追踪受保护的修复策略状态。
当看门狗无法自行修复通道时,channelHealth.healing 现在会显示重启 / 手动策略、连续降级次数、冷却时间、尝试次数、上次结果,以及 manualRepairRequired、manualRepairSummary 和 manualRepairCommands。gateway diagnose 会新增 channel-healing,明确列出操作者手动修复步骤;看门狗可以尝试重启符合重启条件的降级通道,同时将所有权 / 租约冲突留作手动处理 / 操作者处理。
Telegram 的 getUpdates 冲突重试不再被视为健康的回退状态:轮询中断且仅处于重试状态时,所有权约定会在 /health、gateway status 和 gateway diagnose 中明确显示为降级。
低信号操作员垃圾信息防护现在还适用于:
- 将
restate/restate/*来源视为自动化,以便批量处理;成功完成的队列派发 DAG 不会立即触达实时网关会话 - 默认不向操作员发送
test.gateway-e2e - 通过规范的 Redis 信号管道(
slack.signal.received)传递 Joel Slack 被动情报,而不是绕过中继策略 - 使用
packages/gateway/src/operator-relay.ts作为跨 Slack/邮件信号执行规范化 → 评分 → 关联 → 路由的唯一启发式处理入口 - VIP 管道发送直接 Telegram 摘要后,再接收
vip.email.received,使网关保留关联上下文而不发送重复提醒,同时允许低信号邮件/Slack 项根据项目/联系人/对话键合并为关联摘要 - 丢弃仅包含低信号的摘要(仅心跳 / 仅队列派发完成),而不是提示模型生成无意义的
HEARTBEAT_OK - 在静默时段,常规的回退切换/恢复通知不会发给操作员;恢复通知仅写入日志/OTEL,除非有更高信号路径将其升级
- 始终屏蔽仅发给操作员的
Knowledge Watchdog Alert消息;降级的轮次写入统计属于系统维护,而非操作员工作 - 添加主动压缩滞回机制(冷却 30 分钟,除非上下文显著恶化)
- 在再次探测主模型前,要求回退状态至少持续一段时间,避免回退切换→恢复的通知立即抖动
- 当主模型为
claude-opus-4-6时,将fallbackTimeoutMs下限设为240000;120000现已被视为过时,对 Opus 的实际 TTFT 过于激进 - 在收到空或已中止的
message_end事件时立即清除回退超时状态,避免已中止的轮次污染下一轮的延迟/回退监控 - 发出结构化回退决策遥测(
model_fallback.decision),包含原因分类 / 探测次数 / 探测退避信息,以便 OTEL 区分真实的提供商故障和嘈杂的控制循环 - 在主模型恢复探测暂时失败或持续失败后延长退避时间,而不是每个间隔都反复请求同一个故障提供商
- 将压缩/轮换视为明确的维护窗口:在网关状态中显示这些操作、发出维护生命周期遥测,并允许空闲等待/看门狗逻辑为真实维护工作延长等待时间,再判定轮次已失效
静音的降级通道现在也会切换为 manual,并将已知问题原因显示为修复指引,而不是错误地声明一种看门狗在静音期间会跳过的重启策略。
仍未完成:更严格的跨通道所有权强制措施,以及超出 CLI 指引手动步骤范围的、更丰富/原生的修复自动化。
运行时防护措施强制执行(ADR-0189)
网关运行时现在会强制执行两项对操作员可见的防护措施:
- 工具预算检查点触发器
- 通道轮次:超过 2 个工具的预算后强制创建检查点
- 内部/后台轮次:超过 4 个工具的预算后强制创建检查点
- 遥测:
daemon.guardrails:guardrail.checkpoint.*
- 推送后自动验证部署
- 在成功执行
git push后,如果HEAD涉及apps/web/或根目录配置文件(turbo.json、package.json、pnpm-lock.yaml) - 守护进程会在约 75 秒后安排执行
vercel ls --yes 2>&1 | head -10 - 失败时会向 Telegram 发送提醒,并发出
daemon.guardrails:guardrail.deploy_verification.failed
- 在成功执行
使用 joelclaw gateway status 查看实时 guardrails 状态;在检查点或部署验证处于活动状态时,使用 joelclaw gateway diagnose。
行为控制平面(ADR-0211)
网关行为现在明确且确定:
- 运行时权威来源: Redis 活跃合约(
joelclaw:gateway:behavior:contract) - 历史记录/候选项: Typesense
gateway_behavior_history - 写入权威来源: 仅 CLI(
joelclaw gateway behavior ...)
可直接通过 CLI 或在频道中使用严格语法输入操作指令:
KEEP: ...MORE: ...LESS: ...STOP: ...START: ...
网关扩展会被动捕获这些行,并调用 joelclaw gateway behavior add ...。
它不会直接写入 Redis 或 Typesense。
每日审核仅提供建议:候选项由 cron 生成,必须手动通过 joelclaw gateway behavior promote --id <candidate-id> 晋升。
从 Inngest 函数发送事件
每个 Inngest 函数都会通过中间件接收 gateway(ADR-0035):
async ({ event, step, ...rest }) => {
const gateway = (rest as any).gateway as GatewayContext | undefined;
await step.run("notify", async () => {
if (!gateway) return;
await gateway.notify("my.event.type", {
message: "Human-readable summary",
data: "structured-payload",
});
});
}
| 方法 | 用途 | 路由 |
|---|---|---|
gateway.progress(msg, extra?) | 流水线/循环进度 | 来源会话 + 中央网关 |
gateway.notify(type, payload?) | 通知(任务完成、webhook) | 来源会话 + 中央网关 |
gateway.alert(msg, extra?) | 系统警告(磁盘、服务宕机) | 仅中央网关 |
导入:import type { GatewayContext } from "../middleware/gateway";
始终对 gateway 进行空值检查——函数可能在没有网关会话的情况下运行。
底层:pushGatewayEvent()
用于中间件外部的代码:
import { pushGatewayEvent } from "./agent-loop/utils";
await pushGatewayEvent({
type: "video.downloaded",
source: "inngest/video-download",
payload: { message: "Downloaded: My Talk" },
originSession: event.data.originSession,
});
常见故障模式
| 症状 | 可能原因 | 修复方法 |
|---|---|---|
| 状态显示正常,但收不到消息 | 会话卡在挂起工具调用的流处理中 | joelclaw gateway restart |
| 会话上的待处理事件不断增加 | Agent 正在处理或被阻塞 | 检查当前进度和已配置的超时;仅在有证据表明属于修复范围时重启 |
| Telegram 消息未送达 | 响应中的 HTML 解析错误 | 检查 joelclaw gateway status,然后重启 |
| Telegram 被原始入站邮件刷屏 | front.message.received 中继门控过于宽松,或分类器发生偏移 | 检查 packages/gateway/src/operator-relay.ts;原始 Front 邮件仅应在生产/安全/资金故障,或有人直接提出项目相关请求时触发提醒 |
Telegram 被元系统警报(gateway.*、会话压力、Knowledge Watchdog、Slack channel_not_found)刷屏 | 维护/检查事件未被抑制 | 不要将直接的 watchdog/频道/系统警报发送到 Telegram;操作员中继应将元系统消息归类为 suppressed.meta-system-chatter |
| Slack 被动消息流看起来失效(提及仍有效) | 启动时未派生 SLACK_ALLOWED_USER_ID | 确保 slack_user_token 租约正常;gateway-start.sh 会通过 auth.test 派生用户 ID,然后运行 joelclaw gateway restart |
| 未收集重要 Slack 频道 | 缺少 SLACK_IMPORTANT_CHANNEL_IDS/SLACK_IMPORTANT_CHANNEL_NAMES,或频道 ID 已变更 | 检查私有的 ~/.joelclaw/scripts/gateway-start.sh,重启网关,并确认启动日志显示 importantChannelIds > 0 |
| Slack 回复没有默认目标 | 启动时未派生 SLACK_DEFAULT_CHANNEL_ID | 确保 slack_bot_token 租约正常;gateway-start.sh 会通过 conversations.open 派生私信频道,然后重启 |
| 网关每隔几秒就重启 | 崩溃循环——密钥租约异常或代码错误 | 检查 /tmp/joelclaw/gateway.err,并修复原因 |
| Redis 连接失败 | Redis pod 宕机,或 Colima/k8s 底层环境宕机 | 检查 colima status --json,然后通过 joelclaw status/kubectl 检查集群健康状况 |
langfuse-cost 可选依赖警告 | pi 扩展运行时缺少 Langfuse 跟踪依赖 | 仅影响可观测性;不要将其视为消息链路阻塞问题 |
架构
launchd (com.joel.gateway)
└─ gateway-start.sh (leases secrets, sets env)
└─ bun run daemon.ts
├─ createAgentSession() → headless pi session (reads SOUL.md)
├─ Redis channel (joelclaw:notify:gateway)
├─ Telegram channel (@JoelClawPandaBot)
├─ Slack channel (invoke on Joel/mentions; collect configured important channels)
├─ WebSocket (port 3018, for TUI attach)
├─ Command queue (serial — one prompt at a time)
└─ Heartbeat runner (periodic autonomous checks)
模型选择应依据当前启动/配置来源和明确的任务要求。检查该配置及可用的提供方模型;不要从本文档恢复历史模型锁定,也不要悄悄替换所请求的模型。
网关启动时会读取 ~/.pi/agent/,以获取身份/提示词上下文(SOUL.md、AGENTS.md、MEMORY.md、每日日志),但网关扩展本身仅限当前上下文:
- 标准源:
~/Code/joelhooks/joelclaw/pi/extensions/gateway/index.ts - 活动路径:
~/.joelclaw/gateway/.pi/extensions/gateway(符号链接) - 不要全局安装/恢复
~/.pi/agent/extensions/gateway
守护进程启动时会强制执行此约束;如果本地扩展缺失或检测到全局网关扩展,就会启动失败。
这样可以避免网关自动化钩子进入正常的交互式 pi 会话。
关键文件
| 文件 | 用途 |
|---|---|
packages/gateway/src/daemon.ts | 守护进程入口 — 会话创建、渠道、心跳 |
packages/gateway/src/channels/redis.ts | Redis 订阅、排空、提示词构建 |
packages/gateway/src/channels/telegram.ts | Telegram 机器人渠道 |
packages/gateway/src/command-queue.ts | 串行 FIFO 队列 → session.prompt() |
packages/gateway/src/heartbeat.ts | 定期自主任务运行器 |
packages/gateway/src/gateway-alert-investigator.ts | XState 事件生命周期和默认 Herdr DGX GLM 启动器 |
infra/gateway-tripwire.sh | 每五分钟运行一次的心跳传感器和调查器调度器 |
packages/system-bus/src/inngest/middleware/gateway.ts | 注入 gateway 上下文的中间件 |
packages/cli/src/commands/gateway.ts | CLI 子命令 |
~/.joelclaw/scripts/gateway-start.sh | launchd 启动脚本 |
/tmp/joelclaw/gateway.{log,err,pid} | 运行时日志和 PID |
ADR 锚点
- ADR-0213 — 会话生命周期保护和防止频繁重试行为
- ADR-0146 — Langfuse 可观测性集成(缺少可选依赖项时必须以开放模式失败)