# How OpenClaw Integration Forwards Session Events to External Gateways in oh-my-claudecode

> Learn how OpenClaw integration forwards session events to external gateways in oh-my-claudecode. Discover efficient event forwarding without blocking main execution.

- Repository: [Bellman/oh-my-claudecode](https://github.com/Yeachan-Heo/oh-my-claudecode)
- Tags: how-to-guide
- Published: 2026-03-27

---

**OpenClaw integration in oh-my-claudecode uses a fire-and-forget `_openclaw.wake` wrapper that lazily loads a dispatcher to read user configuration, build whitelisted JSON payloads, and forward session events to external command or HTTP gateways without blocking the main hook execution.**

The oh-my-claudecode project implements a lightweight event forwarding system called OpenClaw that streams Claude Code session lifecycle events to external services. This integration allows users to configure custom gateways—either shell commands or HTTP endpoints—that receive structured payloads whenever hooks like `session-start` or `stop` trigger. Understanding how OpenClaw integration forwards session events to external gateways reveals a non-blocking architecture designed for reliability and extensibility.

## Architecture Overview

The OpenClaw system operates through a layered dispatch mechanism that remains dormant until explicitly enabled. At the core, the `_openclaw.wake` wrapper in [`src/hooks/bridge.ts`](https://github.com/Yeachan-Heo/oh-my-claudecode/blob/main/src/hooks/bridge.ts) (lines 1303-1308) serves as the single entry point for all hook implementations. This wrapper performs a lazy dynamic import of the OpenClaw module only when the `OMC_OPENCLAW=1` environment variable is set, ensuring zero overhead when the feature is disabled.

The actual dispatch logic resides in [`src/openclaw/index.ts`](https://github.com/Yeachan-Heo/oh-my-claudecode/blob/main/src/openclaw/index.ts), where the `wakeOpenClaw` function (lines 72-84 and 119-180) orchestrates configuration loading, gateway resolution, payload construction, and final transmission. Gateway resolution logic in [`src/openclaw/dispatcher.ts`](https://github.com/Yeachan-Heo/oh-my-claudecode/blob/main/src/openclaw/dispatcher.ts) determines whether to invoke a shell command via `wakeCommandGateway` or an HTTP request via `wakeGateway` based on the user-defined configuration stored in `~/.claude/omc_config.openclaw.json`.

## The Event Forwarding Pipeline

### Hook Entry Points and the Wake Wrapper

Every relevant session hook—`session-start`, `session-end`, `stop`, `keyword-detector`, and `ask-user-question`—invokes the same forwarding interface. The wrapper checks the environment switch before proceeding:

```typescript
// src/hooks/bridge.ts (lines 1296-1310)
export const _openclaw = {
  wake: (event: string, ctx: OpenClawContext) => {
    if (!process.env.OMC_OPENCLAW) return; // Environment gate
    import("../openclaw/index.js")
      .then((m) => m.wakeOpenClaw(event, ctx))
      .catch(() => {}); // Fire-and-forget: errors swallowed
  },
};

```

This pattern ensures that hooks at [`src/hooks/session-start/index.ts`](https://github.com/Yeachan-Heo/oh-my-claudecode/blob/main/src/hooks/session-start/index.ts) (lines 41-53) and similar entry points can trigger external notifications without awaiting network I/O or risking runtime exceptions.

### Configuration Loading and Gateway Resolution

Upon activation, `wakeOpenClaw` calls `getOpenClawConfig()` from [`src/openclaw/config.ts`](https://github.com/Yeachan-Heo/oh-my-claudecode/blob/main/src/openclaw/config.ts) to read the JSON configuration. If the file does not exist at the default location, the function returns `null` and forwarding aborts silently. Assuming configuration exists, `resolveGateway(config, event)` in [`src/openclaw/dispatcher.ts`](https://github.com/Yeachan-Heo/oh-my-claudecode/blob/main/src/openclaw/dispatcher.ts) (line 46) maps the event name to a specific gateway definition:

```typescript
// Conceptual flow from src/openclaw/index.ts (lines 72-84)
const config = await getOpenClawConfig();
if (!config) return null;

const resolved = resolveGateway(config, event);
if (!resolved) return null; // No gateway mapped for this event

const { gatewayName, gateway, instruction } = resolved;

```

### Payload Construction and Variable Interpolation

Before transmission, the system builds a whitelisted context object via `buildWhitelistedContext` (lines 44-59 in [`index.ts`](https://github.com/Yeachan-Heo/oh-my-claudecode/blob/main/index.ts)) to prevent leaking unintended session data. The dispatcher then prepares template variables including `sessionId`, `projectPath`, `timestamp`, and derived values like `tmuxSession` or `projectName`.

If the configuration instruction contains template variables (e.g., `{{replyChannel}}`), `interpolateInstruction` (lines 149-150) substitutes them using the variables map. The final `OpenClawPayload` object (lines 151-165) assembles the event name, interpolated instruction, timestamp, session metadata, a cryptographic signal from `buildOpenClawSignal`, and the whitelisted context:

```json
{
  "event": "session-start",
  "instruction": "notify-start",
  "timestamp": 1699999999999,
  "signal": "...",
  "context": { "sessionId": "abc123", "projectPath": "/home/user/project" }
}

```

### Dispatch to Command or HTTP Gateways

The system supports two gateway types determined by `isCommandGateway` in [`src/openclaw/dispatcher.ts`](https://github.com/Yeachan-Heo/oh-my-claudecode/blob/main/src/openclaw/dispatcher.ts). The decision block at lines 170-176 in [`index.ts`](https://github.com/Yeachan-Heo/oh-my-claudecode/blob/main/index.ts) routes accordingly:

- **Command gateways**: `wakeCommandGateway(gatewayName, gateway, variables, payload)` executes shell commands with proper escaping, useful for local scripts or `curl` invocations.
- **HTTP gateways**: `wakeGateway(gatewayName, gateway, payload)` performs a `fetch` POST with JSON content.

Both methods operate asynchronously with discarded promises, ensuring the hook continues regardless of gateway health.

## Configuring External Gateways

Users define gateway mappings in [`omc_config.openclaw.json`](https://github.com/Yeachan-Heo/oh-my-claudecode/blob/main/omc_config.openclaw.json). The configuration specifies event-to-gateway mappings, authentication headers, and template variables:

```json
{
  "gateways": {
    "session-start": {
      "type": "http",
      "url": "https://example.com/openclaw/hooks",
      "method": "POST",
      "headers": { "Authorization": "Bearer {{replyChannel}}" }
    },
    "stop": {
      "type": "command",
      "command": "curl -X POST -H \"Content-Type: application/json\" -d '{{payloadJson}}' https://example.com/openclaw/stop"
    }
  }
}

```

The `{{payloadJson}}` variable inserts the entire serialized payload object, while `{{replyChannel}}` and other custom variables interpolate user-defined values from the context.

## Implementation Details and Error Handling

Debug visibility requires setting `OMC_OPENCLAW_DEBUG=1`, which enables result logging to `stderr` (lines 79-82 in [`index.ts`](https://github.com/Yeachan-Heo/oh-my-claudecode/blob/main/index.ts)). By design, all errors are caught and suppressed at the wrapper level (`.catch(() => {})` in [`bridge.ts`](https://github.com/Yeachan-Heo/oh-my-claudecode/blob/main/bridge.ts) line 1308), preventing network timeouts or configuration errors from disrupting the Claude Code session lifecycle.

The `wakeOpenClaw` function returns an `OpenClawResult` object or `null` on failure (lines 183-190), though the wrapper discards this return value to maintain the fire-and-forget contract.

## Summary

- **Entry point**: The `_openclaw.wake` wrapper in [`src/hooks/bridge.ts`](https://github.com/Yeachan-Heo/oh-my-claudecode/blob/main/src/hooks/bridge.ts) provides a fire-and-forget interface that checks `OMC_OPENCLAW=1` before lazily loading the OpenClaw dispatcher.
- **Configuration**: `getOpenClawConfig()` reads `~/.claude/omc_config.openclaw.json` to map events to specific command or HTTP gateways.
- **Payload building**: The system constructs whitelisted contexts, interpolates template variables like `{{payloadJson}}`, and generates cryptographic signals for verification.
- **Non-blocking dispatch**: Gateway resolution in [`src/openclaw/dispatcher.ts`](https://github.com/Yeachan-Heo/oh-my-claudecode/blob/main/src/openclaw/dispatcher.ts) routes to either `wakeCommandGateway` or `wakeGateway`, with all promises discarded to prevent hook blocking.
- **Silent failure**: Errors are swallowed by design, with optional debug logging available via `OMC_OPENCLAW_DEBUG=1`.

## Frequently Asked Questions

### What environment variables are required to enable OpenClaw event forwarding?

The `OMC_OPENCLAW=1` environment variable must be set to activate the integration. Without this flag, the `_openclaw.wake` wrapper returns immediately without loading the dispatcher. For troubleshooting, set `OMC_OPENCLAW_DEBUG=1` to print gateway results to `stderr`.

### How does oh-my-claudecode prevent session data leakage when forwarding events?

The dispatcher uses `buildWhitelistedContext` (lines 44-59 in [`src/openclaw/index.ts`](https://github.com/Yeachan-Heo/oh-my-claudecode/blob/main/src/openclaw/index.ts)) to filter the incoming `OpenClawContext` object before adding it to the payload. This whitelist approach ensures only explicitly defined fields (such as `sessionId` and `projectPath`) are transmitted, preventing accidental exposure of sensitive session internals.

### Can I use shell scripts instead of HTTP endpoints for OpenClaw gateways?

Yes. Set the gateway `type` to `command` in your [`omc_config.openclaw.json`](https://github.com/Yeachan-Heo/oh-my-claudecode/blob/main/omc_config.openclaw.json) configuration. The system will invoke `wakeCommandGateway` from [`src/openclaw/dispatcher.ts`](https://github.com/Yeachan-Heo/oh-my-claudecode/blob/main/src/openclaw/dispatcher.ts), which executes the specified shell command with the payload available via template variables like `{{payloadJson}}`. This enables integration with local notification scripts, custom logging tools, or alternative HTTP clients.

### Where does the OpenClaw configuration file live by default?

The system looks for [`omc_config.openclaw.json`](https://github.com/Yeachan-Heo/oh-my-claudecode/blob/main/omc_config.openclaw.json) at `~/.claude/omc_config.openclaw.json` unless overridden. The `getOpenClawConfig()` function in [`src/openclaw/config.ts`](https://github.com/Yeachan-Heo/oh-my-claudecode/blob/main/src/openclaw/config.ts) reads this location; if the file is missing, the forwarding operation aborts silently without throwing errors.