Public: anyone can read this; the crew can change it.

One share verb: share(item, to?) routes to who needs to know, with budgets against noise #370

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

`share(item, to?)` now exists as `POST /api/v1/share` and as an MCP `share` tool. `tsc` is clean and the new `test/share.test.ts` (11 tests) passes. The feed, MCP, kernel, migrate and parity tests also pass. I did not run the full `forge.json` check, which also covers many other suites.

shipped production is serving it deploy 7cfd21c

opened this

share(item, to?) now exists as POST /api/v1/share and as an MCP share tool. tsc is clean and the new test/share.test.ts (11 tests) passes. The feed, MCP, kernel, migrate and parity tests also pass. I did not run the full forge.json check, which also covers many other suites.

What changed

  • Routing with no target: the app's crew and owners (an org's writers and admins) get it first. Only if none of them is someone other than the sender does it fall back to people who pinned the app (org members only, when an org owns it). Named usernames (up to 10) are always added. "Follow" is the existing pin, since the repo has no other follow concept.
  • No widening: a recipient must canRead the repo and have that exact item among their own feed candidates. Otherwise they are unreachable, which is also what an unknown username gets. The sender must see the item too, or the call is a 404.
  • Agents: an agent is steered with a comment when the item is a change, and told (an issue routed to a builder) otherwise. Both go through addCommentThrough and tell as the sender, so the sender's own rights apply.
  • People: a person gets a share: feed item whose reason is "shared by X: …". It replaces the plain item and is boosted by 3 × sender weight. Shares to people are stored in a new share table (migration 36), with src/core/shares.ts for the data and src/feed/share.ts for the verb.
  • Noise control:

- Each person gets 5 delivered shares a day. - Extra shares queue, are delivered best-weighted first as room frees (checked on each feed read), and are dropped after 48 hours. - There is one share per item per recipient, ever. - Sender weight is 2·(opens+1)/(shares+2) over 90 days, clamped to 0.2–2. - A recipient who muted the app skips the share, and dismissing the item hides it. - A share also records a shared interaction for the sender.

  • Also touched: rank.ts and items.ts gain an optional said reason override. forge.json's check now includes test/share.test.ts, and docs/FEED.md has a Sharing section.

Left out

  • There is no share button or page.
  • Agents have no budget, only the per-item dedupe.
  • The first non-empty routing tier wins rather than adding all of them, to keep noise down.
  • Checking each recipient's candidates reads their whole feed sources, which is fine at the cap of 10 recipients.

To try it

bun test test/share.test.ts
curl -X POST -H "authorization: Bearer $T" -H 'content-type: application/json' \
  -d '{"item":"event:<id>","to":["bob"]}' $FORGE_URL/api/v1/share

Bob's GET /api/v1/feed then shows the boosted item.

🤖 Generated with Claude Code

Closes #362

commented

I merged main into the branch and pushed it. The merge conflicted in docs/FEED.md and forge.json, and I kept both sides in each.

  • docs/FEED.md: main added a "The page" section and this branch added "Sharing". Both are in, with the page section first.
  • forge.json: main added test/feed-page.test.ts to the check. I kept that line and added test/share.test.ts after it.

tsc is clean, and test/share.test.ts, test/feed.test.ts and test/feed-page.test.ts all pass (32 tests). I did not run the full forge.json check locally.

commented

I merged main into the branch and pushed it. The merge conflicted in docs/FEED.md, forge.json and src/http/feed.ts, and I kept both sides in each.

  • docs/FEED.md: main added an "Offline" section. It now sits alongside "Sharing".
  • forge.json: main added test/offline.test.ts to the check. I kept that line and added test/share.test.ts after it.
  • src/http/feed.ts: main's POST /api/v1/feed/tells route and this branch's POST /api/v1/share route are both registered, and parseTargets is kept.

tsc is clean, and test/share.test.ts, test/feed.test.ts, test/feed-page.test.ts and test/offline.test.ts pass (43 tests). I did not run the full forge.json check locally.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs