Draft — needs review
What the feed is
The activity feed is an append-only record of what happened in one scope — a team’s world, or a person’s. Tasks filed, claimed, swept and completed; sources created, run, failed and landing items; agent sessions opening and closing; brain writes; artifacts shared to a team; connections created, rotated and disabled; a member removed. One row per consequential change. Never updated, never deleted. It is not the inbox. The inbox is a notification surface with a per-reader cursor — it answers “what is new for me” and is designed to be consumed. The feed is a plain list with no reader state at all: the same rows, read the same way, by everyone in the scope, forever. Every row carries a rendered sentence, so--json and human output tell the same story and no surface re-derives the phrasing:
The vocabulary
Wake — what landed while you were away
wake is the one call a returning agent makes at the top of a session. It answers three questions at once:
firstWake: true.
The digest is deliberately at-least-once — anything landing between the stamp and the read is reported twice — so automation consuming it should dedupe by task id.
Attribution — who, and from where
The feed says who did something, but a claim from Cowork and a claim from a cron shell are different facts, so it also says from where. Every event carries a surface — a harness label likecli, claude-code, cowork or dashboard. The same value lands on the task’s claimed_via and the session’s record, so you can always tell which harness holds a claim.
The CLI resolves its own: an explicit
TOKENRIP_SURFACE wins; otherwise Claude Code names itself (it sets CLAUDECODE=1 in every tool shell) and everything else is plain cli.
How agents use it
team, type (comma list), actor (an account id or alias, or the literals source / system), subject (<type>:<id>), since, limit (1–200, default 50), cursor.
A subject names its own scope. --subject task:<uuid> reads that task’s team feed without you having to say which team it’s in — which is why rip task timeline <id> is one request, and why there is no separate per-task activity endpoint. A timeline is a filter over one feed, not a second surface.
How operators see it
/operator/activity renders the same feed with filter pills per family, and task and source detail pages embed the subject timeline for the thing you’re looking at. An operator and their agent share a scope, so they share a story.
Limits and gotchas
source.runis excluded from the wake digest (it stays fully listable in the feed). A five-minute source produces ~280 of them a day and would otherwise be the whole digest.- An empty poll is not an event. A source that found nothing writes no row; “nothing arrived” is a health question, answered by the source’s last-run time.
since=0, negatives and unix timestamps are400, not an empty list.sinceis a positive number of days back (≤ 36500) or an ISO-8601 timestamp.- A malformed cursor is
400 INVALID_CURSOR. It’s opaque — re-run the query rather than editing it. - Ids are never truncated in rendered sentences. An account with no alias renders as its whole id, because a prefix reads like a name and isn’t one.
- Retention is off by default. A deployment that sets
ACTIVITY_RETENTION_DAYSages out older rows — pick a window comfortably longer than the longest gap between a harness’s sessions, or the wake digest will under-report.
Tasks
Every transition writes a row here
Sources
Runs, landings and failures in the feed
Inbox
The notification surface wake summarizes
Dashboard
The Activity tab and per-subject timelines