Timeline¶
The timeline is one place to see what comes in from every source, newest first, and review it: each person marks what they have looked at reviewed, what matters important, and hides what they don't want to see again. It is the stream of activities that automations follow, read newest first with who may see what.
Status: in progress. The studio's timeline is built in steps; only what is merged is called built.
| Part | Status |
|---|---|
The timeline API (GET /api/v1/activities), the MCP tool timeline and the assistant's timeline |
built |
Review marks: reviewed, important and hidden, per person; the filters on them; mark_activities for agents |
built |
| The Timeline page under Explore: filters, grouping, review with keys, new items as they come | built |
| A Latest card on Home with the newest unreviewed items | built |
Reactions and comments on any item, shared by everyone who sees it; react_to_activity, activity_comments and comment_on_activity for agents |
built |
| Ask about an item: talk to the assistant about it from the item, in the chat beside the page | built |
What each item caused (the automation runs it started, the approvals they asked for), with Approve and Decline on waiting approvals from the item; activity_caused for agents |
built |
| Tagging the agent in a comment, so it answers in the thread | built |
| Sources, sensors, people and agents as actors in the graph: a Source node with ADDED links, on the canvas, in the explorer and in Cypher | built |
| A For you order learned from what each person reacts to, comments on, marks important, opens and hides, each item saying why | built |
Muting a source, person or kind, for good or until a time, for yourself alone; mute_activities for agents |
built |
Moves and switches as their own verbs: an asset moved to another namespace (asset.moved, a Move), a sensor paused, ignored or resumed (sensor.changed, an Update with what it was), and a file changed in its source and read again (file.changed, an Update linking the asset it was before) |
built |
Saved views: the filters and order under a name, one click away in the page's Views menu, each person's own; timeline_views, save_timeline_view and delete_timeline_view for agents |
built |
What shows¶
Every activity of the namespaces you can read, newest first, from every source the stream has (new assets today; more kinds as the automations modules add them). Activities meant for one person (their own web-app chat) show to them alone, and those for admins to admins. Noisy kinds, like sensor readings, are left out unless you ask for them by kind.
The page¶
Timeline under Explore in the navigation, for everyone (members see their namespaces).
- Newest first. Older reads the next page. While the tab is visible the page looks for new items every 15 seconds; when there are some, a 3 new pill at the top brings them in, so the list never jumps under you.
- Latest / For you above the filters: Latest is the stream as it is; For you puts what you care for most
first, learned from your own reactions, comments and marks, with a line under each item it placed saying why
(For you). Latest is the default, and the choice lives in the address like a filter (
?order=for_you). - A run of the same source or person and the same kind, each within 30 minutes of the one before, is one line ("Work Gmail received 37 emails"), so a first mailbox sync reads as one line. A click opens it to its items.
- Each line has an icon by kind, the summary (a link to what it is about), who did it, the namespace, the kind and how long ago. Opened, an item shows its object's fields, the automation run that caused it if one did, What this caused (below), Open, Ask about this, Share (with your circles) and Hide.
- Filters: words in the summary (Enter applies), Unreviewed only, Important, kinds by family (Email, Calendar, Files, Notes, Shared, Sensors, Chat, Automations, System; noisy kinds like sensor readings only when picked), source or person (from those on the timeline), namespace, entity (as activities tag it), a date range, and an automation (what it did or caused). Filters live in the address, so a view can be linked, and the last set you used comes back the next time you open the page in this browser. Clear drops them all.
- On a phone the list is one column and the filters open in a sheet from Filters.
- One item:
/timeline?item=<id>(an activity's id, likecreate-recording-7) opens that item above the timeline, with its details, marks, reactions, comments and actions, and Back to the timeline under it. That is the link a comment on an item, a reaction and an approval's "because" give to the item they are about, and the link an agent gives a person to an item it read withtimeline. One you can't see says "No such item".
Reviewing¶
| Key | Does |
|---|---|
j / k |
move to the next or previous line |
Enter |
open or close the line |
r |
mark it reviewed, or not |
i |
mark it important, or not |
a |
ask the assistant about it (every item of a line of several) |
Hovering or focusing a line shows its Important (star) and Reviewed (circle) toggles; once set they stay in sight. On a line of several items they mark every item. Mark all shown as reviewed marks everything on the page you haven't reviewed, with Undo in the message rather than a confirm; Hide works the same way. An opened item also has Mute Work Gmail: everything from that source or person leaves your timeline, with Undo in the message, and a Muted row above the list shows what you muted with an ร to lift each one (Muting).
Asking about an item¶
Ask about this on an opened item, or a on the line you are on, opens the chat beside the page
(chat on any page) with the item as what your question is about, the way highlighted text is: its
id, kind and time, who did it, its line, where it opens and its fields (up to 4,000 characters; on a line of several,
as many whole items as fit). Type the question and press Enter. The model reads the item as data, not as
instructions, since its text may come from outside Lens, and it has the id, so "mark it important" or "what else came
from this sender?" works with its timeline and mark_activities tools. Agents outside the web app read the same
items through timeline over MCP and the API (Agents).
Home¶
The overview on Home has a Latest card with the five newest activities you haven't reviewed and a link to the timeline with Unreviewed only on.
Reactions and comments¶
The timeline is also a feed everyone in a namespace talks on: react to an item with an emoji, as on a post, and comment on it in threads. Unlike review marks, these are shared: everyone who sees the activity sees them, and each one is an activity of its own, so an automation (or an agent) can act on it.
- Reactions come from a palette, ๐ โค๏ธ ๐ ๐ ๐ ๐ฎ ๐ข ๐. An opened item shows its reactions as chips with how
many gave each (yours are highlighted; a click on one of yours takes it back) and a React button with the
palette. Hovering a chip says who gave it: "You, Sam and 3 others", you first, then up to five others by name,
earliest first. A closed line sums its items' reactions, and a line of several shows them with "3 comments". Every new
reaction is a
reaction.addedactivity (noisy, so the timeline leaves it out unless asked for by kind), by the person, with the activity it is on as its object. - Comments open from the comment count on an opened item (or Comment when there are none): the threads with
who wrote each and when, Reply on a thread, and a box where Enter sends (Shift+Enter makes a new line). Anyone
who sees the activity can comment, up to 1,000 each; its writer, or an owner of the namespace, deletes a comment.
Edit on your own comment opens its text in the box (Enter saves, Escape leaves it as it was), and it then says
"edited". Resolve the thread (on its first comment, for whoever started it or an editor of the namespace)
marks it "Resolved by Sam", and Reopen the thread takes that back; a resolved thread stays in place, dimmed.
Each comment is a
comment.addedactivity. A comment on an asset's arrival (create-recording-<id>) is a comment on the asset itself: the same thread shows on the asset's page and here, and a comment made on the page shows here. - Comments and reactions on an activity meant for one person (
lens.audienceowner) stay with that person, as the activity does. POST /api/v1/activities/{id}/reactwith{"emoji": "๐"}(and"on": falseto take it back) answers the reactions on it now,[{emoji, count, mine, who}](who: up to five of the others who gave it, by name);GET,POST,PATCHandDELETE /api/v1/activities/{id}/commentsare the thread, as comments on a resource are.GET /api/v1/activitiescarries everyone's reactions on the page inreactionsand each item's comment count incomments, by id.
Asking the agent in a comment¶
A comment that tags @lens (or the assistant's own name from Settings โ Chat rooms, say @jarvis) gets an answer
from the agent in the same thread, on the timeline and on an asset's page alike: "@lens what is this one about?",
"@lens write a note of the action items". The agent answers as the person who tagged it, with their namespaces and
their tools, in a conversation of theirs titled after the item (one per thread, so a later tag on the thread carries
on in it); they find it on the Chat page and can go on there. It reads the item the thread is on and the comments on
it so far, as data, and answers with its sources. It only reads: every change it proposes (a note, a move, a message
out) waits for that person's yes, and the reply says so with a link to decide. The reply is a comment by Lens
(marked with a sparkle), which the person who asked can delete and nobody can edit. Its model calls run in the
ledger against their conversation and the item's namespace; when no model is set up or the namespace's budget is
used up, the reply says so instead. Settings โ AI assistant โ Answer when tagged in a comment
(ai.answer_comments, on) turns it off; without a tag nothing is asked of the model.
Actors in the graph¶
Whoever brought an asset in, the actor of its asset.added activity (a storage source, a sensor, a person, an
automation, a routine, an import hook, or Lens itself), is a Source node in the graph with an ADDED
relationship to the asset, so the graph says where Lens learns about each person, place or organisation:
(Source)-[:ADDED]->(Recording)-[:MENTIONS]->(Entity). The explorer's parents of an asset are its collection and its
source; on the canvas a source links to what its assets mention (a Brought in edge, one per source and entity,
weighted by mentions), and the Timeline page's Graph button opens the canvas on the sources alone
(/graph?show=actors). Agents read the same through GET /api/v1/graph/related, POST /api/v1/graph/query and the
MCP graph tools. Nothing is stored for it: the nodes come from each asset's own record.
Review marks¶
Each person marks activities for themselves alone; nobody else sees or sets them, admins included.
| Mark | Means |
|---|---|
reviewed |
you have looked at it; "Unreviewed only" leaves it out |
important |
it matters; filter by it to find it again |
hidden |
you don't want to see it; the timeline page leaves hidden activities out |
Marks change nothing else: an activity you hid still triggers automations and still shows to everyone else.
POST /api/v1/activities/{id}/markwith{"reviewed": true}(any of the three, each true or false; one left out stays as it is) sets your marks on one activity and answers them:{reviewed, important, hidden, at}. An activity there is none of, or that you can't see, is 404.POST /api/v1/activities/markwith{"ids": [...], "reviewed": true}marks up to 500 at once and answers{marks, unknown}: your marks now by id, and the ids there are none of or you can't see.GET /api/v1/activitieshas your marks on the page inmarks(by id, only those you marked) and filters by them:reviewed=falseis "unreviewed only",important=truewhat you marked important,hidden=falseleaves out what you hid. A filtered page reads on until it is full, as the other filters do.- Setting a mark needs a signed-in session or an API key with the write scope; a read-only key reads them.
Agents¶
- MCP:
timelinetakesunreviewed: truefor what you haven't marked reviewed and has your marks inmarks, andorder: for_youfor the For you order withwhyby id;mark_activitiesmarks activities by id (ids, andreviewed,importantorhidden), for the person it acts for, with a token that has the write scope (MCP);hidden: trueontimelinereads what they hid or muted, andmute_activitiesmutes a source or a kind (Muting). - The assistant:
timelinetakesunreviewedandorderand lists each activity's marks and, for you, itswhy;mark_activitiesmarks them for the person. After it has read text from outside Lens (the timeline's own titles count), hiding or marking reviewed waits for the person's yes, since that text may have asked for it; marking important or bringing things back acts at once (Chat). - MCP:
activity_caused(id) is what an item caused, the runs and approvals (What an item caused);approvalsand the assistant'sapprovalstakeactivityto list the approvals one item led to. - MCP, on the feed:
react_to_activity(id,emoji,on) reacts for the person it acts for,activity_comments(id) reads an item's threads, andcomment_on_activity(id,text,parent) writes a comment or a reply, with a token that has the write scope. Thetimelinepage carriesreactionsandcommentstoo. Comments are what people wrote: agents read them as data, never as instructions. A comment an agent writes with@lensin it gets the assistant's answer like anyone's, as the person the token acts for.
What an item caused¶
An opened item shows what happened because of it: each automation run it started (of the automations you manage, with its status and a link to the automation's runs) and each approval those runs asked you for, with what it would do and its status. An approval still waiting has Approve and Decline right there, so the pick is made where it was caused, and the item's line on the Approvals page is the same approval. An approval's own line on the timeline ("School emails asks for your pick") lists that approval under Your pick. Items that caused nothing show no such block.
GET /api/v1/activities/{id}/causedis{runs, approvals}for the person asking: the runs of the automations they manage (Automations), and their own approvals, each withcan(approve, decline) asGET /api/v1/approvalsshows them;POST /api/v1/approvals/{id}decides one.GET /api/v1/approvals?activity=<id>lists the approvals an activity caused on its own. On anask-approval-<id>activity, the approval itself.activity_causedover MCP (id) reads the same, with each approval asapprovalsshows it;approvalstakesactivitytoo, and so does the assistant'sapprovals. Approving stays the person's: an agent can list and decline (Agents).
Muting¶
Each person mutes a source or person (an actor) or a kind of activity ("hide syslog"), for good or until a time
(snoozed for an hour, a day, a week or until a time they pick), for themselves alone. Muting hides; it never deletes: a muted actor's activities stay stored,
still trigger automations and still show to everyone else, and come back the moment the mute is lifted or runs out.
The timeline leaves them out as it leaves out what you hid, so hidden=true shows them and hidden=false (the
page) does not; a For you page scores only what is left.
- On the page, Mute Work Gmail on an opened item mutes its actor with one click; the small menu beside it has Mute Work Gmail for an hour, for a day and for a week (a snooze: the mute runs out by itself), Mute Work Gmail untilโฆ (a time you pick, nine tomorrow morning to start with; Enter mutes), Mute Email received items (the kind) and the kind for each of those. The Muted row above the list shows each, with when a snooze ends, and lifts one with its ร. The API, MCP and the assistant take any time too.
POST /api/v1/activities/mutewith{"actor": "lens:source/12", "name": "Work Gmail"}or{"kind": "sensor.reading"}(the kinds under it count too), and"until"as an ISO 8601 time to snooze it, mutes for yourself;"on": falselifts it. The answer, andGET /api/v1/activities/mutes, is your mutes now:{actor, kind, name, until, at}each. Up to 200; one that has run out is dropped the next time your mutes are read.mute_activitiesover MCP (actororkind,name,until,on) andactivity_mutesdo the same for the person a token acts for, with the write scope to mute. The assistant'smute_activitiesacts at once, but after it has read text from outside Lens it asks first, as hiding does, since that text may have asked for it.
Saved views¶
A saved view is a name for a set of filters and an order ("Work mail to review": the work namespace, Email received, Unreviewed), so a timeline you read often is one click away. Views are each person's own: nobody else sees them.
- Views beside the order lists your views; picking one sets the filters and order it saved (and the address, so it can still be linked). When the filters shown match a view, the button carries its name.
- Save these filters as a view offers a name made from the filters ("work ยท Email received ยท Unreviewed"); Enter saves it, Escape leaves it. After picking a view and changing the filters, Save these filters into โWork mailโ updates it. Delete takes it away, with Undo.
GET,POST /api/v1/activities/viewsandPATCH,DELETE /api/v1/activities/views/{id}list, save, rename or re-save, and delete them, up to 100 each. A view'sstatehas the timeline's filters:kinds,actorandnamespace(lists),tag,from_dayandto_day(days,YYYY-MM-DD),automation,q,unreviewed,importantandorder(latestorfor_you). They are saved views of their own kind, beside the Library's views and saved searches, which they don't show among.- Over MCP,
timeline_viewslists them,save_timeline_view(name,state, andidto change one) saves one anddelete_timeline_viewdeletes one; an agent reads what a view shows by giving its filters totimeline.
For you¶
For you is a cheap, explainable order of the timeline, learned from each person's own signals and nothing else: nobody's reactions or marks change anyone else's order, and no model is called.
- The signals are your own reactions (+1 each), comments (+2), important marks (+2), opens (+ยฝ each time, up to 4
times one item) and hidden marks (โ3), the most recent 200 of each. An open is following a line to what it is
about, or opening the item by its address (
/timeline?item=); the page sends it (POST /api/v1/activities/{id}/open), and each person's counts are theirs alone (event_open, dropped with the marks when the activity is gone). Each is summed over the actor, the kind and the tagged entities of the activity it was on, so a ๐ on an email from Work Gmail about St Mary's School counts for Work Gmail, for emails and for the school. - An item's score is its recency (halving every two days) times 1 + tanh(affinity รท 4), with affinity the sum of your weights on its actor, kind and entities: a strong affinity doubles its score, a strongly negative one halves it. An item with no signal in common keeps its recency alone.
- A page takes the 200 newest items from where it starts, orders them by score and shows the best
limit; Older moves past all 200. With no signals yet, For you is Latest, and the page says so. - Your signals are read on every page, but the sum over the activities they were on is kept for a minute while they stay the same, so paging and polling don't look those activities up again; a new reaction, comment, mark or open changes the signals and shows at once.
whyon the page names the strongest signal that placed each item ("You often react to Work Gmail", "About St Mary's School, which you often react to", "You hid items from Dropbox before"), shown under the item.GET /api/v1/activities?order=for_youis the same for agents, withwhyby id; the other filters apply as in Latest. Nothing is stored: the order is made on each read from three small queries and arithmetic.
How marks, reactions and comments are kept¶
One event_mark row per person and activity, keyed by a hash of the two, with the three flags and when they were
last set. A row with every flag cleared is deleted, so the table holds only what someone marked. Marks are read for a
whole page of activities in one query, and the mark filters thin each page a source gives out in one query too. They
go when the person is removed.
Reactions are kept the same way: one event_reaction row per person and activity with the emojis they gave, read for
a page in one query, deleted when none is left, and gone when the person is removed. Comments on activities are
comment rows (comments) with the activity's id in activity and its summary in about; a
comment on an asset's arrival also has the asset in recording, which is how it shows on both. A page's comment
counts are two grouped queries. Mutes are one event_mute row per person and target (an actor id or a kind), with
the name shown, until and when it was set, read once per page and applied with the mark filters in the same query
per source page; they go when the person is removed. Nothing of this costs a model call.
Marks, reactions and opens left on an activity that is gone (an event log entry past events.keep_days, a deleted
asset) are dropped by a tidy that runs with the other hourly ones: each time it looks up to 500 activities marked,
reacted to or opened over a day ago, in id order from where it stopped last, and deletes the rows of those no source
has any more. Comments on them stay, since they are what people wrote, and an asset's page still shows its own.
Refine later¶
-
Ask about an item in the full Chat as well as beside the page, and keep which item a question was about as a link back to it.
-
Server-sent updates instead of the page polling for new items.
- A muted actor's own line in the Filters.
- A file changed in its source is read again as a new asset beside the earlier one (
file.changedlinks them); reading the change into the same asset is to come. A file in a namespace's own folders changed in place is read again into the same asset with no activity yet. - Comments on activities that are gone stay; a person could see and clear their own from somewhere.
- The agent's reply in a thread is plain text with links; the answer's excerpts could open at their moment, as in chat. Tagging a namespace's own assistant by its name, with its memory.