mib007's mention path is fixed (Nirlabinc/mib007 PR #32): mention resolution is now fire-and-forget server-side (a lookup failure can no longer 500 the POST after the insert), and an @handle matching an active workspace-member user's lower(name) creates a comment.mention notification. - update_body: the needs-you escalation line now emits a real @handle instead of the zwsp-neutralised one, so the human actually gets pinged. - neutralize() stays for all ledger-derived text (titles/details/notes): item text containing @aros/@ellie must not accidentally fire an agent reply. - bridge.env: PULSE_BRIDGE_MENTION nir -> rapidnir. 'nir' resolves to nothing (mentions match lower(user.name) over ACTIVE workspace members; the only human members of Nirlab Command Center are Board and RapidNir). Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01YECpkAwQUwgu7NVy91R8fW
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 atseen), 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.envnext to the script (orPULSE_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 inatorder. 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:
cp ai.shre.pulse-bridge.plist ~/Library/LaunchAgents/
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/ai.shre.pulse-bridge.plist
v1 intake (reverse direction)
New top-level posts in the activity channel written by a human (not the
bridge, not agent accounts, not π€-prefixed, not mirror posts carrying a
ledger: tag line) become executed, tracked background work.
Prefix a post with π¬ (or chat:) to just talk β chat-only posts are
never turned into a ledger item or task and the bridge never replies to
them. The prefix list is configurable via PULSE_BRIDGE_INTAKE_OPTOUT
(comma-separated, case-insensitive).
- Ledger item β
shre-items add --kind pipeline --stage queued --tag pulse-intake, title = first 80 chars of the post, detail = full post + post id. The ledgerβpost map is seeded with the USER'S post id before the item'sop:addreaches the feed, so the outbound mirror adopts the user's post instead of creating a duplicate. - Kanban task β
hermes kanban create β¦ --created-by pulse-bridge --idempotency-key pulse-<post id> --jsonon the default board; the Hermes embedded-gateway dispatcher picks it up (~60 s). Cap: max 3 concurrent intake-spawned tasks; overflow posts getβ³ queued behind N tasksand start when a slot frees. - Acknowledgment β comment
π€ picked up β ledger <id>, kanban <task>on the user's post. - Tracking β each poll reads
kanban list --jsononce; on a status change it comments (βΆοΈ running/β blocked/β completed β <result>) and advances the ledger item (running β stage build; done β closed with--why "kanban <id> completed").
Intake state (intake_checkpoint epoch-ms + postβledgerβtask map) lives in
the same atomically-written state.json. First intake run only sets the
checkpoint to the newest existing post β history is never ingested.
Intake caveats (accepted, reviewer-flagged)
- Status/ack comments are best-effort: a crash between a state save and its
comment can drop or (once) repeat a comment. Ledger and kanban stay
consistent β
shre-items doneon a closed item is a logged no-op and--idempotency-key pulse-<post id>adopts the existing task on retry. - Bridge-output filtering is content-based (user name,
π€prefix,ledger:tag line, threaded); renaming the poster or ignore list while old posts are inside the intake window could ingest bridge output. The comms API has no structured message metadata to mark authorship.
v0/v1 limitations
- No real user-mention primitive. mib007 comms has agent @mentions
only (the first
@handlein 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 path is broken on this instance (found during smoke): ANY
@handlein a message makesPOST β¦/messages500 after the row is inserted β the mention agent-lookup queries a nonexistenturl_keycolumn onagents(comms.ts~line 226; error in mib007 stderr log). Retrying such a failure duplicates the message. The bridge therefore (a) zwsp-neutralises every@it emits, including its own@nirescalation (renders identically in the UI), and (b) treats an HTTP error on a comment as non-retryable (DROP β¦ comment not retriedin the log) β comments are best-effort; posts still retry. - 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.