@loggie-ai/openclaw-plugin
v0.1.7
Published
OpenClaw channel plugin for Loggie meeting transcript events.
Readme
Loggie OpenClaw Plugin
OpenClaw channel plugin for Loggie meeting transcript events.
The plugin opens an outbound authenticated WebSocket to Loggie, replays from the
last durable cursor, and turns each meeting.transcript.ready event into one
OpenClaw inbound channel turn for the configured agent.
How It Works
- OpenClaw loads the setup-safe entrypoint for discovery, config inspection, status, doctor checks, and SecretRef target discovery.
- When the configured channel account starts, the full runtime entrypoint lazy loads the WebSocket monitor.
- The monitor opens a WebSocket to
baseUrl + socketPath, authenticating with eitherAuthorization: Bearer <token>orx-api-key: <token>. - Before opening the socket, the plugin loads the durable cursor from OpenClaw
trusted runtime state when available, otherwise from the file-backed cursor
store, and appends it to the URL as
?cursor=<lastCursor>. - Loggie sends event envelopes. The plugin validates the envelope, skips
duplicates or cursor regressions, and processes
meeting.transcript.ready. - If the event includes
payload.detailPath, the plugin fetches that detail from the same Loggie origin with the same auth header. Cross-origin detail URLs are rejected before auth headers are attached. - The plugin builds a deterministic OpenClaw session key from the agent, account, and meeting id, records the inbound route, and runs the configured OpenClaw agent with the transcript prompt.
- The cursor advances only after dispatch succeeds, or after an unsupported event is intentionally skipped.
Loggie Server Contract
Minimum server-side behavior expected by this plugin:
- Authenticated WebSocket endpoint at
/api/events/socketby default. - WebSocket auth using the configured agent profile token.
- Initial replay from the WebSocket URL query:
?cursor=<cursor>. - Durable event ordering using
eventIdand monotonic stringcursor. - Client messages
{ "type": "ping" }and{ "type": "resume", "cursor": "..." }. - Replay pagination control messages:
{ "type": "loggie.events.more_available", "cursor": "..." }. meeting.transcript.readyevent envelopes.- Optional HTTP detail endpoint referenced by
payload.detailPath. - Control messages with
type: "hello","ack", or"pong"are accepted and treated as connection/control traffic.
Example event:
{
"cursor": "123",
"type": "meeting.transcript.ready",
"payload": {
"eventId": "evt_1",
"cursor": "123",
"type": "meeting.transcript.ready",
"workspaceId": "ws_1",
"meetingId": "mtg_1",
"meetingScheduleId": "sched_1",
"title": "Weekly Standup",
"source": "recall_ai",
"externalId": "tr_1",
"meetingDate": "2026-06-26T11:30:00.000Z",
"hasTranscript": true,
"detailPath": "/api/proxy/meetings/sched_1"
},
"createdAt": "2026-06-26T12:00:00.000Z"
}The plugin also accepts the older internal envelope shape and { "event": { ... } }
wrappers for compatibility, but the server socket shape above is the primary
contract.
Configuration
Configure the channel under channels.loggie.
{
"channels": {
"loggie": {
"enabled": true,
"baseUrl": "https://loggie.example.com",
"agentProfileId": "ap_123",
"credentialRef": "$LOGGIE_AGENT_TOKEN",
"agentId": "main"
}
}
}Important fields:
baseUrl: Loggie HTTP origin. Defaults toLOGGIE_BASE_URL, thenhttp://127.0.0.1:8787.socketPath: WebSocket path. Defaults to/api/events/socket.agentProfileId: Loggie agent profile used for socket auth and OpenClaw sender/account identity. Server events are workspace-scoped and do not need to include this field.credentialRef: Token input. Use$ENV_VARfor env-backed credentials or a structured SecretRef. If OpenClaw materializes a SecretRef before runtime, the resulting string is treated as token material.token: Literal token fallback for local development.authHeader:authorizationby default, orx-api-key.agentId: OpenClaw agent id that should receive transcript turns. Defaults tomain.reconnect.minMsandreconnect.maxMs: exponential reconnect backoff bounds.heartbeat.timeoutMs: stale socket timeout. Defaults to120000.
Environment defaults:
export LOGGIE_BASE_URL="https://loggie.example.com"
export LOGGIE_AGENT_TOKEN="..."For multiple accounts, put account-specific settings under
channels.loggie.accounts:
{
"channels": {
"loggie": {
"accountId": "prod",
"accounts": {
"prod": {
"baseUrl": "https://loggie.example.com",
"agentProfileId": "ap_prod",
"credentialRef": "$LOGGIE_AGENT_TOKEN",
"agentId": "main"
}
}
}
}
}Sessions And Cursoring
Session identity is deterministic:
- Route session key:
agent:<agentId>:loggie:<accountId>:meeting:<meetingScheduleId|meetingId|eventId> - Embedded run session id:
loggie-<accountId>-<meetingScheduleId|meetingId|eventId>
The cursor store is always durable. Trusted OpenClaw installs use
runtime.state.openKeyedStore({ namespace: "loggie-cursors" }). Plain external
npm installs that do not receive the trusted runtime state API fall back to a
file-backed store at runtime.state.resolveStateDir()/loggie-cursors.json when
OpenClaw exposes a state directory, or ~/.openclaw/state/loggie-cursors.json
otherwise. Startup does not fail solely because trusted state is unavailable,
and the fallback still persists replay cursors across gateway restarts.
The plugin keeps a bounded set of recently seen event ids and skips:
- duplicate
eventId - lower numeric
cursorvalues than the stored cursor
If transcript dispatch fails for the same event, the plugin records the failure
in the durable cursor state and retries inside the plugin after 5 seconds, 10
seconds, then 15 seconds. After 4 failed dispatch attempts, the event is
recorded in deadLetteredEvents, the cursor advances, and later events can
continue processing. The latest dead-letter is also reported in channel status
as lastDeadLetterAt, lastDeadLetteredEventId, lastDeadLetteredCursor,
lastDeadLetterReason, and lastDeadLetterAttempts, and the monitor emits a
warning log.
Reconnect And Heartbeat Behavior
Unexpected socket errors or closes reconnect with exponential backoff. The
next socket URL includes the last persisted cursor so Loggie can replay missed
events. If Loggie reports loggie.events.more_available, the plugin sends
{ "type": "resume", "cursor": "..." } to request the next replay page.
The plugin sends periodic { "type": "ping" } messages. The heartbeat timeout is
based on any received socket message, including pong and other control
messages. When the heartbeat expires, the plugin closes the socket and waits for
in-flight event handling to finish before reconnecting. That avoids dispatching
the same transcript twice while an earlier turn is still advancing the cursor.
Security Notes
- Tokens are used only for outbound Loggie auth headers.
- Status and inspect output report token availability/source, not token values.
- Detail fetches are restricted to the configured Loggie origin.
credentialRefshould be$ENV_VARor a structured SecretRef for config. Plain strings are treated as materialized token values.
Development
npm install
npm run check
npm test
npm run build
npm run preflightUseful targeted commands:
npm run plugin:inspect
npm run plugin:inspect:runtime
npx tsc -p tsconfig.json --noEmit --noUnusedLocals --noUnusedParameters
npm pack --dry-runnpm run preflight runs typecheck, tests, build, and both plugin-inspector
passes.
