# pulse-bridge v0 Mirrors the estate's shared work ledger (`~/.local/bin/shre-items`, JSONL store at `~/.shre/open-items/items.jsonl`) into **Pulse** — the social-feed surface of the local mib007 instance (`http://127.0.0.1:5520`, launchd `ai.shre.mib007`). Ledger items become posts, stage changes become threaded comments, needs-you escalations mention the user. ## Where Pulse actually lives (as discovered 2026-08-22) The Pulse UI is mib007's **Activity** app (`/activity`, `PULSE_ROUTE` in `ui/src/platform/lib/app-routes.ts`). Its feed is backed by the **comms** tables, not the unified message envelope: the envelope work (`feed_items` view, migrations 0101-0111) is in shreai PR #163 and is **not merged** into the running mib007 (local checkout is at migration 0100). The `/api/workspaces/:id/feed` route proxies to shre-feed (:5436), which is **down** locally. So the write path Pulse really uses is: - create post: `POST /api/workspaces/:wid/comms/channels/:cid/messages` `{content, type: "text", userName}` → returns the row (`id` = post id) - comment/reply: same endpoint with `threadId: ` - channel: the Activity app reads/writes the channel named `activity` (creates it if missing) — same behaviour here. Auth: mib007 service token (`~/.shre/service-tokens.json`, key `mib007`), board-level, valid from loopback. mib007 runs in `authenticated` mode, so requests without it are rejected. ## Mapping | ledger op | Pulse action | |---|---| | `add` | new post: emoji by kind + title, detail, tag line (`#kind #stage #tags surface: project: ledger:`) | | `update` | comment on the mapped post: `stage → review`, `⛔ failed at verify, attempt 2 — `, `kind → …` | | `update` to `kind: needs-you` | comment `@nir NEEDS YOU: …` | | `close` | comment `✅ done — ` or `🗑 dropped — ` | First run seeds posts for **currently-open items only** (`shre-items list --json`); history before the bridge is not replayed. ## State & config - State: `~/.shre/pulse-bridge/state.json` — checkpoint (`max at` seen), boundary-second `(id,op,at)` dedupe set (the feed window is inclusive), ledger-id → post-id map, resolved channel id. Written atomically (tmp + `os.replace`). - Config: `bridge.env` next to the script (or `PULSE_BRIDGE_ENV`); environment variables override. See the file for keys (poll interval, mib base URL, workspace, channel, mention handle, token file). - Poll cadence: every 30 s the daemon runs `shre-items feed --since ` and processes new records in `at` order. A failed record stops the batch **before** the checkpoint advances past it, so it is retried next cycle. ## launchd `ai.shre.pulse-bridge` — KeepAlive daemon, logs to `~/.shre/pulse-bridge/bridge.log`: ```sh cp ai.shre.pulse-bridge.plist ~/Library/LaunchAgents/ launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/ai.shre.pulse-bridge.plist ``` ## v0 limitations - **No real user-mention primitive.** mib007 comms has *agent* @mentions only (the first `@handle` in a message that matches a workspace agent triggers an AI reply). There is no user mention/notification hook, so needs-you escalations are the literal text `@nir NEEDS YOU: …`. - **Mention trap defence:** all ledger-derived text has `@` neutralised with a zero-width space so an `@ellie` in an item detail can never trigger an AI reply in the feed. Only the bridge's own `@nir` (which matches no agent, hence inert) is emitted raw. - Updates for items that pre-date the bridge and were never seeded (closed before first run) are skipped with a log line — there is no post to comment on. - One workspace, one channel. Multi-workspace fan-out is v1. - Fork-links (post → ledger deep link and back) and reverse intake (posting in Pulse creating/annotating ledger items) are **v1**. - Reactions on posts are not mirrored back to the ledger. - If the envelope migration (shreai #163) lands and Pulse moves to `feed_items`, the write path here must be revisited.