Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
eced5a1
Add OpenClaw bridge package skeleton
May 16, 2026
a388a23
Add OpenClaw bridge registration config
May 16, 2026
5905c34
Add OpenClaw agent room registry
May 16, 2026
313886f
Add OpenClaw approval response mapping
May 16, 2026
41b9fc6
Add OpenClaw gateway runtime wrapper
May 16, 2026
043966c
Add OpenClaw Matrix bridge coordinator
May 16, 2026
7252973
Add OpenClaw bridge management CLI
May 16, 2026
8b59e29
Add OpenClaw Pickle bridge connector
May 16, 2026
2974170
Add OpenClaw session backfill planning
May 16, 2026
cbf35b6
Wire OpenClaw history into bridge backfill
May 16, 2026
2ba589d
Add OpenClaw Beeper setup helpers
May 16, 2026
4918041
Add OpenClaw HTTP gateway transport
May 16, 2026
5922ca4
Add OpenClaw Beeper bridge runtime
May 16, 2026
c449f8a
Persist OpenClaw Beeper account identity
May 16, 2026
75b2fcb
Add OpenClaw bridge start command
May 16, 2026
d460ca3
Support Beeper account creation in OpenClaw setup
May 16, 2026
c6e401d
Model OpenClaw session users as ghosts
May 16, 2026
afeeabe
Add OpenClaw WebSocket gateway transport
May 16, 2026
b28f9fd
Expose broader OpenClaw gateway features
May 16, 2026
2d89f80
Add OpenClaw session backfill executor
May 16, 2026
adcb310
Normalize OpenClaw gateway stream events
May 16, 2026
58cfd37
Add OpenClaw protocol coverage manifest
May 16, 2026
f75e8b4
Document OpenClaw bridge package usage
May 16, 2026
a7c03ef
Wire OpenClaw startup backfill
batuhan May 16, 2026
7b6fce6
Force non-federated OpenClaw portals
batuhan May 16, 2026
227f644
Expose OpenClaw gateway RPC management
batuhan May 16, 2026
00a8a11
Create sessions for OpenClaw agent DMs
batuhan May 16, 2026
60ba686
Merge remote-tracking branch 'origin/main' into batuhan/oc-2
May 24, 2026
514a1a9
Refactor core workflow and supporting modules
May 24, 2026
51d4bdf
Remove gateway token fallback from OpenClaw bridge
May 25, 2026
485850a
Refine pickle openclaw plugin packaging and session handling
May 25, 2026
b38b4d9
Stream OpenClaw runs through AG-UI channel replies
May 25, 2026
b33f1c2
Require native OpenClaw channel turns for Beeper streaming
May 25, 2026
6a06ccd
Fix Beeper plugin to stream AG-UI responses natively
May 25, 2026
7475c36
Propagate Matrix room ids into OpenClaw turns
May 25, 2026
d58a809
Fix Beeper streaming and approval tool-call shapes
May 25, 2026
94a36cf
Stream Beeper tool output and handle OpenClaw slash commands
May 26, 2026
584b067
Add HTML formatting to OpenClaw command replies
May 27, 2026
41644c2
Rewrite OpenClaw as a first-class Beeper network connector
May 27, 2026
cb8fc40
Refactor pickle data flow and UI state handling
May 27, 2026
739e0ec
Sync openclaw manifest schema with bridge config
May 27, 2026
2e805e6
Enable native Beeper stream identities and tool streaming
May 27, 2026
7274fad
Handle Codex tool stream events without false positives
May 27, 2026
1c6b06c
Rename OpenClaw package and remove plan files
May 27, 2026
97207e4
Update beeper runtime and client operation types
Jun 1, 2026
7bee27a
sync
Jun 2, 2026
0349ca5
Refactor bridge core for bridgev2 room state handling
Jun 2, 2026
28cac3c
Push ghost profiles through bridgev2 appservice intents
Jun 2, 2026
090c8ee
Fix Beeper rich stream finalization
Jun 2, 2026
c4d9f2e
wip
Jun 2, 2026
8e6eb49
Add multi-account Beeper onboarding
batuhan Jun 2, 2026
0de2f1d
Add Beeper account auth presence
batuhan Jun 2, 2026
2dd203d
Fix OpenClaw bridge release checks
batuhan Jun 3, 2026
ad054c3
Build packages before CI tests
batuhan Jun 3, 2026
b15b435
Avoid deep OpenClaw plugin test comparisons
batuhan Jun 3, 2026
8670bca
Increase OpenClaw CI smoke test timeouts
batuhan Jun 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,15 @@ jobs:
- name: Typecheck
run: pnpm typecheck

- name: Build
run: pnpm build

- name: Test
run: pnpm test

- name: Go test
run: pnpm test:go

- name: Build
run: pnpm build

- name: Pack packages
run: pnpm pack:packages

Expand Down
40 changes: 40 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# OpenClaw plugin

Use Crabpot for OpenClaw plugin and integration compatibility testing. Crabpot is the OpenClaw compatibility testbed for community plugins, plugin API seams, channel registration, lifecycle hooks, provider capabilities, cold imports, workspace planning, and static execution policy.

Expected sibling checkouts:

```sh
/Users/batuhan/Projects/pickle
/Users/batuhan/Projects/crabpot
/Users/batuhan/Projects/openclaw
```

If Crabpot is missing, set it up from the Pickle repo with:

```sh
git clone https://github.com/openclaw/crabpot.git ../crabpot
npm --prefix ../crabpot install
npm --prefix ../crabpot test
```

Crabpot defaults to `../openclaw` for source-mode OpenClaw checks. Clone `https://github.com/openclaw/openclaw.git` there when the checkout is missing, or set `CRABPOT_DIR=/path/to/crabpot` when Crabpot lives elsewhere.

Run the full Pickle and OpenClaw plugin compatibility suite with:

```sh
npm run full-test
```

That runs Pickle's existing `pnpm check` first, then `npm run check` in Crabpot through `scripts/openclaw-crabpot-full-test.mjs`.

Useful narrower commands:

```sh
npm run test:openclaw:plugins
npm --prefix ../crabpot run check
npm --prefix ../crabpot run report -- --check
npm --prefix ../crabpot run workspace:plan
```

Crabpot default checks are credential-free. Do not run opt-in isolated execution commands unless the task explicitly needs side effects, for example `CRABPOT_EXECUTE_ISOLATED=1 npm --prefix ../crabpot run workspace:execute -- --fixture <fixture>`.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,7 @@
- Node file storage, Cloudflare KV storage, and Durable Object storage helpers.
- Matrix messages, room threads, reactions, media, DMs, typing, read receipts,
long polling, and Chat SDK adapter mapping.
- OpenClaw Beeper channel plugin for exposing OpenClaw agents and sessions over
Beeper/Matrix, including setup metadata, appservice registration, agent ghost
contacts, command discovery, approval handling, and native Beeper turn
streaming.
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Requires Node 22+, pnpm 9+, and a Go toolchain.
pnpm typecheck
pnpm test
pnpm build
go test ./... # run from packages/pickle/native
pnpm test:go # runs Pickle's Go tests with the goolm build tag
```

## Release
Expand Down
303 changes: 303 additions & 0 deletions OPENCLAW_BEEPER_HANDOFF.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,303 @@
# OpenClaw Beeper Handoff

Date: 2026-06-02
Workspace: `/Users/batuhan/Projects/pickle`

## Installed Locations

- Pickle/OpenClaw bridge workspace: `/Users/batuhan/Projects/pickle`
- Live installed OpenClaw plugin: `/Users/batuhan/.openclaw/extensions/beeper`
- OpenClaw app source for reference: `/Users/batuhan/Projects/openclaw`
- ai-bridge source for reference and shared-package changes: `/Users/batuhan/Projects/ai-bridge`
- mautrix bridge examples/reference: `/Users/batuhan/Projects/mautrix`
- plugin validation harness: `/Users/batuhan/Projects/crabpot`

Live channel status at handoff:

```sh
openclaw channels status
```

Reports:

- Gateway reachable.
- Beeper default: enabled, configured, running.
- Telegram default: enabled, configured, running, connected. This is unrelated to the Beeper/OpenClaw bridge work.

## Original Product Goal

Build `@beeper/openclaw` as a first-class Beeper plugin backed by Pickle and bridgev2 semantics.

Target model:

- `UserLogin`: one Beeper/OpenClaw account/device.
- `Ghost`: one global OpenClaw agent user.
- `Portal`: one Matrix/Beeper conversation.
- `Session`: OpenClaw runtime state attached to a portal only after the first real user turn.

Expected behavior:

- Each configured OpenClaw agent gets a stable global ghost:
`@<bridge_id>_agent_<agent_id>:<server>`.
- Each agent gets one welcome DM portal on connect.
- Users can start new DMs/groups with those ghost users.
- A new DM/group creates or claims a portal.
- The first real user message in that portal creates an OpenClaw session and persists `sessionKey` on the portal binding.
- Importing old OpenClaw sessions is explicitly later work and should not shape the core bridge.

Constraints from Batuhan:

- Use bridgev2/mautrix mental model as much as possible.
- Move as much logic as possible into Go and generated Go contracts.
- Reuse ai-bridge packages heavily, but do not import ai-bridge `internal` or connector-specific code.
- Keep code simple: no fake layers, no duplicate types, no barrel exports for convenience, no backcompat, no legacy migration baggage.
- Prefer deleting/collapsing code over preserving AI-generated parallel paths.
- Beeper-only setup. Do not expose homeserver/domain/token/appservice id as ordinary user settings.
- Product intent beats current code shape.

## Current Implementation Status

Important current git state:

```sh
git status --short
```

At handoff, modified files include:

- `packages/bridge/src/bridge.ts`
- `packages/bridge/src/bridge.test.ts`
- `packages/bridge/src/index.ts`
- `packages/openclaw/src/bridge-agent.ts`
- `packages/openclaw/src/connector.ts`
- `packages/openclaw/src/connector.test.ts`
- `packages/openclaw/src/openclaw-runtime.ts`

Do not assume all modifications are from the last agent turn. The tree has been evolving across multiple turns.

### ai-bridge Dependency

Pickle native Go helpers are pinned to the latest local ai-bridge commit we used:

```text
github.com/beeper/ai-bridge v0.0.0-20260602005818-ab83be648105
```

Local ai-bridge HEAD:

```text
ab83be648105 / ab83be64 Preserve tool metadata in final AI parts
```

This is in `packages/pickle/native/go.mod`. `go.sum` still contains the older pseudo-version too, which is normal unless cleaned by `go mod tidy`.

### Streaming / Beeper AI

Main stream logic lives in:

- Go/native: `packages/pickle/native/internal/core/beeper_ai_run.go`
- TS bridge stream adapter: `packages/bridge/src/beeper-stream.ts`
- OpenClaw runtime mapper: `packages/openclaw/src/openclaw-runtime.ts`
- OpenClaw channel runtime: `packages/openclaw/src/beeper-channel-runtime.ts`

Current state:

- Native Go path uses ai-bridge writer/projection/finalization.
- Finalization and large final parts upload are in Go through ai-bridge projection helpers.
- Semantic parts include text, reasoning, tool start/input/result, activity, state, raw/custom events.
- Tool result mapping now prefers actual stdout/stderr/response over status wrapper objects.
- Working placeholder suppression exists in both text and activity paths. The latest edit suppresses activity events whose visible text is exactly `Working...`.
- Pending tools are waited on before finalization in the TS runtime path.
- Final projection clears ai-bridge `Working...` fallback bodies for empty streams.

Known streaming gaps:

- Need live Beeper Desktop confirmation that rotating progress verbs render exactly like ai-bridge.
- Reasoning/thinking tokens depend on what OpenClaw emits. The bridge now maps reasoning events, but if OpenClaw emits no reasoning stream, Beeper will show none.
- The current rich stream mapper is still partly TypeScript. The long-term direction is more generated Go contracts and less TS mapping.
- Need compare against ai-bridge stream semantics again before calling this done, especially sequence ordering and final replacement behavior.

### Ghosts / Portals / Sessions

Main files:

- `packages/openclaw/src/connector.ts`
- `packages/openclaw/src/bridge-agent.ts`
- `packages/openclaw/src/registry.ts`
- `packages/openclaw/src/rooms.ts`

Current state:

- Agent ghosts are registered globally from OpenClaw agents.
- Agent contacts are exposed through contact list / identifier resolving.
- Each agent gets a welcome DM portal on connect.
- Welcome portal bindings are `kind: "agent"` with placeholder `sessionKey: "agent:<id>"`.
- On first real user turn, `OpenClawMatrixBridgeAgent.ensureSession()` creates a real OpenClaw session and now changes the binding to `kind: "session"`.
- The first user message in a welcome room therefore transitions from agent/welcome binding to a real session binding.
- Users can resolve agent ghosts and create fresh DMs.

Known portal/session gaps:

- Need deeper audit against bridgev2 examples in WhatsApp/Telegram/Signal for exact portal claiming, invite/group handling, and room metadata lifecycle.
- Need live test starting a new DM/group with an agent ghost from Beeper Desktop.
- Need ensure reconnect does not create duplicate welcome DMs after an agent binding has become a session binding. Current code uses the agent binding as the welcome-room marker, so this area needs attention after the new transition.
- Need improve ghost avatar/name syncing from OpenClaw agent metadata and verify desktop displays them correctly.

### Slash Commands

ai-bridge handles slash commands before the AI turn and replies with a command notice. OpenClaw previously parsed slash commands but still passed the slash text to the agent as prompt text.

Current state:

- `packages/openclaw/src/matrix-parser.ts` parses slash commands.
- `packages/openclaw/src/connector.ts` now intercepts OpenClaw `/help` and `/session`.
- `/session` is sent as an `m.notice` from the agent ghost or service bot, not as an AI turn.
- `/session` in a welcome room reports that no real session has started yet and does not create one.
- Unknown slash commands still fall through to OpenClaw as agent text for now.

Known command gaps:

- Need implement real `/stop`/`/abort` only after finding or adding a real OpenClaw cancellation primitive. Do not fake cancellation.
- Need decide which commands belong to OpenClaw channel runtime vs bridge control.
- Need richer formatting if Beeper Desktop supports a better command-result surface than `m.notice` HTML.

### Config / Setup

Current public Beeper channel settings are intentionally minimal:

- `enabled`
- `beeperEnv` with production as default

Public schema:

- `packages/openclaw/src/beeper-channel-config.schema.json`
- `packages/openclaw/openclaw.plugin.json`

Hidden persisted setup still includes appservice/homeserver/tokens/device data under channel settings. Do not expose these as normal user settings.

Login/setup direction:

- Email login is default.
- Username/password is optional.
- Token auth should be removed from user-facing setup.
- The bridge owns and persists its Beeper device.
- Appservice / bridge id should be derived per device. Do not ask for values that can be derived.
- `mode: "self-hosted-appservice"` and `registrationUrl: "websocket"` should be hardcoded through bridgev2/Pickle defaults, not user-configurable.

## Bridge Manager / Appservice Flow

Bridge-manager helper code:

- `packages/bridge/src/beeper.ts`
- Exports from `packages/bridge/src/index.ts`

The helper mirrors useful `bbctl whoami/register` pieces:

- `createBeeperBridgeManagerClient({ token })`
- `fetchBeeperBridges({ token })`
- `createBeeperAppService({ token, bridge })`
- `createBeeperAppServiceInit({ token, bridge })`

Flow:

1. Call Beeper API `https://api.<domain>/whoami`.
2. Get username and bridge-manager/Hungryserv metadata.
3. Register or fetch appservice through Hungryserv:
`/_matrix/asmux/mxauth/appservice/:user/:bridge`.
4. Register with `self_hosted: true`, `receive_ephemeral: true`.
5. Post bridge state back to Beeper bridgebox with state events like `STARTING`, `RUNNING`, etc.
6. Produce `MatrixAppserviceInitOptions` with homeserver, homeserver domain, and registration tokens.

Runtime startup:

- OpenClaw channel startup is in `packages/openclaw/src/setup.ts`.
- It calls `startOpenClawBeeperBridge()` from `packages/openclaw/src/appservice.ts`.
- `startOpenClawBeeperBridge()` creates the Pickle bridge, starts it, and marks bridge state running.
- `packages/bridge/src/bridge.ts` boots Matrix, initializes appservice, loads persisted portals/logins, subscribes Matrix events, and starts websocket appservice transaction handling.
- If appservice registration URL is websocket/self-hosted, `AppserviceWebsocket` receives appservice transactions and feeds Matrix events into the bridge connector.

## Restart / Live Sync Commands

After changing `packages/openclaw`, rebuild and sync the installed plugin:

```sh
pnpm --filter @beeper/openclaw build
rsync -a --delete --exclude node_modules /Users/batuhan/Projects/pickle/packages/openclaw/ /Users/batuhan/.openclaw/extensions/beeper/
openclaw plugins registry --refresh
openclaw gateway restart
openclaw channels status
```

If native Go/Pickle code changes, build Pickle too:

```sh
pnpm --filter @beeper/pickle build
pnpm --filter @beeper/openclaw build
rsync -a --delete --exclude node_modules /Users/batuhan/Projects/pickle/packages/openclaw/ /Users/batuhan/.openclaw/extensions/beeper/
openclaw plugins registry --refresh
openclaw gateway restart
openclaw channels status
```

The `rsync --delete` command overwrites the live installed plugin from the workspace package while preserving `node_modules`.

## Useful Validation Commands

Focused tests that passed most recently:

```sh
pnpm --filter @beeper/openclaw test -- src/connector.test.ts src/openclaw-runtime.test.ts
```

Result: 16 files passed, 129 tests passed.

Native Go tests used earlier:

```sh
cd /Users/batuhan/Projects/pickle/packages/pickle/native
go test ./internal/core -run 'TestBeeperAIRun|TestAppservice'
```

OpenClaw broader tests used earlier:

```sh
pnpm --filter @beeper/openclaw test -- src/openclaw-extension.test.ts src/setup.test.ts src/config.test.ts src/beeper-setup.test.ts src/appservice.test.ts
pnpm --filter @beeper/openclaw build
```

Current warning:

```sh
pnpm --filter @beeper/openclaw typecheck
```

Currently fails in `packages/bridge/src/bridge.ts` and `packages/bridge/src/events.ts` with exact optional property/type errors. This was observed after the latest slash/stream edits. Do not treat the typecheck baseline as clean until those bridge-package errors are handled.

## Recent Decisions

- Do not include Beeper account secrets in repo docs or config. Credentials were only provided in chat for live login.
- Do not expose homeserver, domain, hs/as token, appservice id, bridge id, Matrix device id, import/backfill, or approval behavior as public OpenClaw channel settings.
- Keep `additionalProperties: true` in the channel schema for hidden setup state, but public schema and manifest only advertise user-facing settings.
- Slash commands that are bridge commands should not enter the agent prompt.
- Do not implement `/stop` as a fake bridge notice. It needs a real OpenClaw cancel API.
- Preserve ai-bridge semantics for streaming and finalization; if behavior differs from ai-bridge, treat that as a bug unless product intent says otherwise.
- Use actual tool output in Beeper UI, not wrapper/status-only payloads.
- Welcome room is not a session until first real user turn.
- Reasoning is enabled for Beeper sessions by patching OpenClaw sessions with `reasoningLevel: "on"` where supported.

## Highest Priority Next Gaps

1. Fix `@beeper/openclaw typecheck` by cleaning the bridge package type errors.
2. Re-run build and sync live plugin.
3. Live-test from Beeper Desktop:
- fresh welcome DM per agent;
- first real message creates one session;
- `/session` is a notice and not an AI prompt;
- no visible `Working...` flash;
- tool parts stream in order;
- command output shows actual stdout/response;
- search/fetch/source results render with rich parts.
4. Compare connector lifecycle against `/Users/batuhan/Projects/mautrix` WhatsApp/Telegram/Signal examples and bridgev2 expectations.
5. Move more stream/finalization/contract logic into Go and generated types.
6. Add real cancellation support if OpenClaw exposes or can expose an active-run abort method.
7. Revisit welcome-room marker logic after `kind: "agent"` transitions to `kind: "session"` so reconnect does not create duplicate welcome rooms.
Loading
Loading