"Operate the joelclaw gateway daemon — the always-on pi session that receives events, notifications, and messages. Use the joelclaw CLI for ALL gateway operations. Use when: 'restart gateway', 'gateway status', 'is gateway healthy', 'push to gateway', 'gateway not responding', 'telegram not working', 'messages not going through', 'gateway stuck', 'gateway debug', 'check gateway', 'drain queue', 'test gateway', 'stream events', or any task involving the gateway daemon."
Resources
2Install
npx skillscat add joelhooks/joelclaw/gateway Install via the SkillsCat registry.
Gateway Operations
The gateway daemon is the always-on pi session that receives events from Inngest functions, Telegram, and webhooks. It's the system's notification and communication layer.
Rule: Always use joelclaw gateway CLI. Never use launchctl, curl, or log file grep directly.
CLI Commands
joelclaw gateway status # Sessions, queue depths, Redis health
joelclaw gateway restart # Roll daemon, clean Redis, fresh session
joelclaw gateway test # Push test event, verify delivery
joelclaw gateway push --type <type> [--payload JSON] # Push 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 restart is the canonical restart. It kills the process, cleans Redis state, waits for launchd to respawn, and verifies the new session. Never use launchctl bootout/bootstrap directly.
Quick Triage
Run in order, stop at first failure:
joelclaw gateway status # 1. Is it alive? Sessions registered?
joelclaw gateway test # 2. Can events flow end-to-end?
joelclaw gateway events # 3. Are events piling up? (backpressure)
joelclaw gateway restart # 4. If stuck, restartIf joelclaw gateway status shows pending > 0 on sessions, the agent is mid-stream or stuck. If it persists after a minute, restart.
Sending Events from Inngest Functions
Every Inngest function receives gateway via middleware (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",
});
});
}| Method | Purpose | Routing |
|---|---|---|
gateway.progress(msg, extra?) |
Pipeline/loop progress | Origin session + central gateway |
gateway.notify(type, payload?) |
Notifications (task done, webhook) | Origin session + central gateway |
gateway.alert(msg, extra?) |
System warnings (disk, service down) | Central gateway only |
Import: import type { GatewayContext } from "../middleware/gateway";
Always null-check gateway — functions can run without a gateway session.
Low-Level: pushGatewayEvent()
For code outside the middleware:
import { pushGatewayEvent } from "./agent-loop/utils";
await pushGatewayEvent({
type: "video.downloaded",
source: "inngest/video-download",
payload: { message: "Downloaded: My Talk" },
originSession: event.data.originSession,
});Common Failure Modes
| Symptom | Likely Cause | Fix |
|---|---|---|
| Status shows healthy but messages don't arrive | Session stuck mid-stream on hung tool call | joelclaw gateway restart |
| Pending events growing on a session | Agent processing or blocked | Wait 1min, then joelclaw gateway restart |
| Telegram messages not delivered | HTML parsing error in response | Check joelclaw gateway status, restart |
| Gateway restarts every few seconds | Crash loop — bad secret lease or code error | Check /tmp/joelclaw/gateway.err, fix cause |
| Redis connection failed | Redis pod down | joelclaw status to check k8s health |
Architecture
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)
├─ WebSocket (port 3018, for TUI attach)
├─ Command queue (serial — one prompt at a time)
└─ Heartbeat runner (periodic autonomous checks)The gateway reads ~/.pi/agent/ at boot, which includes SOUL.md (§ Agency: "act, don't narrate"), AGENTS.md, MEMORY.md, and today's daily log. This is the layer that has the system philosophy — downstream agents (codex, claude) get clean technical prompts.
Key Files
| File | Purpose |
|---|---|
packages/gateway/src/daemon.ts |
Daemon entry — session creation, channels, heartbeat |
packages/gateway/src/channels/redis.ts |
Redis subscribe, drain, prompt build |
packages/gateway/src/channels/telegram.ts |
Telegram bot channel |
packages/gateway/src/command-queue.ts |
Serial FIFO queue → session.prompt() |
packages/gateway/src/heartbeat.ts |
Periodic autonomous task runner |
packages/system-bus/src/inngest/middleware/gateway.ts |
Middleware injecting gateway context |
packages/cli/src/commands/gateway.ts |
CLI subcommands |
~/.joelclaw/scripts/gateway-start.sh |
launchd start script |
/tmp/joelclaw/gateway.{log,err,pid} |
Runtime logs and PID |