pulse-bridge v0: mirror shre-items ledger into Pulse (mib007 comms) posts
- daemon polls shre-items feed every 30s with inclusive-window (id,op,at) dedupe - op:add -> post in 'activity' channel; op:update -> threaded comment (stage/kind/attempt/note, needs-you escalation mentions @nir); op:close -> done/dropped comment - first run seeds currently-open items only - state (checkpoint + ledger->post map) atomic at ~/.shre/pulse-bridge/state.json - launchd ai.shre.pulse-bridge (KeepAlive, logs to bridge.log) - '@' in ledger-derived text neutralised (zwsp) so comms agent-mention regex can never fire an AI reply from item content Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01YECpkAwQUwgu7NVy91R8fW
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
# 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: <post message id>`
|
||||
- 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:<id>`) |
|
||||
| `update` | comment on the mapped post: `stage → review`, `⛔ failed at verify, attempt 2 — <note>`, `kind → …` |
|
||||
| `update` to `kind: needs-you` | comment `@nir NEEDS YOU: …` |
|
||||
| `close` | comment `✅ done — <why>` or `🗑 dropped — <why>` |
|
||||
|
||||
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 <checkpoint>` 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.
|
||||
Reference in New Issue
Block a user