LifeLab · header lens

The page filter was a lens all along

That meta line — [all] · [page] 2 · :project/lifelab: 4 — already had the parts: [all]/[page] is a source toggle, tag pills are facet chips with counts. Upgrade: clicking a pill activates it into a chip, / opens the same completion line as every picker and funnel, and the result filters everything the page shows — river, subpages, linked, transcluded regions. Stacking rule: intersection. Header state is view state — remembered per page, ephemeral until you pin or name it.

Pills → chips

Passive counts are one click from being filters. Same {} grammar, same completion, zero new UI vocabulary.

Intersection stacking

Header lens ∧ region lens. Rows a region would show but the page lens hides render dimmed, struck — you can always tell which filter bit.

The state ladder

this visit (view state) → pinned to page (page property) → named (lens/…). Same ladder as buffers: ephemeral, resident, citizen.

One line of text, still

Pinned header lens serializes as a page property — lens: todo when:-3w.. — grep-able, sync-safe, MCP-writable like everything else.

1PILL → CHIP

Click a count, get a filter — / for everything else

On the journal day page: :project/lifelab: pill clicked → chip with ×. / opened the completion line, todo half-typed. Non-matching river blocks dim in place (org-agenda honesty) — count line reads 3 of 9. The unsaved lens pill appears the moment the header diverges.

2026-07-12
[all] · [page] · :project/lifelab:× todo · :mcp:3 :nested-pages:2 ◎ unsaved · 3 of 9
completing — status
todoopen tasks3 of current
-taskno marker4
dates
when:this-weekJul 6 – 129
remind:overdue..yesterday + todo1
*TODOwire sql views for tags + links:project/lifelab: :sql:
*TODOdecide region badge copy:project/lifelab:
*planning sunday
*hello — testing:testing:

6 dimmed by header lens · matching blocks stay put — nothing reflows under you

+ Add to journal/2026-07-12… born matching: :project/lifelab: applied
/journal/2026-07-12 header lens · 3 of 9 · unsaved
pills are counts until clicked · / types the rest · esc clears the whole header lens
2STACKING · THE LADDER

Header ∧ region — and where the state goes when you keep it

Header lens {todo} stacked on a region with its own {when:-3w..}: the region row hidden by the page lens renders dimmed with the culprit named. Clicking the unsaved pill opens the ladder: this visit (default — view state, same place day/week/month already lives), pin to page (a property line on the page), name it (lens/).

2026-07-12
[all] · [page] · todo× · :project/lifelab:4 ◎ unsaved · 5 of 12
[-] mcp page · referenced when:-3w..× 2 of 9 · ∧ page lens
*TODO expose query_open over mcp:mcp: Jul 8
* sketch auth handshake notes hidden by page lens: todo
*TODO write mcp tool for lens summon:mcp: Jul 9
*TODOdraft header-lens spec:project/lifelab:
*planning sunday
keep todo ?
just this visit view state · default
clears when you leave
pin to this page page property
lens: todo · applies on load
name it… lens/ · summonable,
appears in ![[ picker
/journal/2026-07-12 header ∧ region · both visible
two lenses, one row:the dimmed line names which lens hid it. region chips stay local; header narrows everything
3WHOLE-PAGE FACE

project/lifelab with the header lens across river · subpages · linked

The big-page face is three sections; the header lens bites all of them, each reporting shown of total. Subpages keep their identity — matches render under their subpage header, so structure survives filtering. [all] vs [page] stays the source toggle: [all] descends into subpages, [page] is direct blocks only.

project/lifelab
[all] · [page] · todo× when:-3w..Jun 21 →× · :sql:2 :mcp:2 ◎ pinned to page
page2 of 14
*TODO ship lens spec:project/lifelab: Jul 11
*TODO decide chip hover affordance Jul 10
+ Add to project/lifelab… born matching: TODO applied
subpages3 of 21 · in 2 of 3 subpages
▤ mcp2 of 9
*TODO expose query_open over mcp Jul 8
*TODO write mcp tool for lens summon Jul 9
▤ sync1 of 7
*TODO CRDT merge test on lens property Jul 2
▤ archive0 of 5 — folded
linked1 of 6
journal/2026-07-091
*TODO benchmark wasm sqlite on mobile:project/lifelab: Jul 9
nproject/lifelab pinned lens · 6 of 41 across 3 sections
pinned: this page opens filtered for everyone until unpinned. property line on the page: lens: todo when:-3w..
4FINAL CHECK

![[Projects]] ![[Reading]] vs ![[Projects, Reading]] — both legal, different meanings

Stacked = two windows: independent fold/close/lens, drag to reorder — but a shared filter is written twice and there's no cross-set sort. Union = one set: one lens, unified sort/group — write-home stays per sub-river. Comma is safe: slugified titles exclude , (like :), and picks store IDs anyway.

a · stacked — two windows

[-]Projects todo× 2 of 14 ×
*TODO ship lens spec
*TODO chip hover affordance
+ Add to Projects
[-]Reading todo× 1 of 5 ×
*TODO finish raskin ch. 4
+ Add to Reading
+ independent fold / close / reorder
+ different lens per window
shared filter typed twice, drifts
no cross-set sort or group

b · union — one set, one lens

[-]Projects, Reading union · 2 pages todo× sort:updated× 3 of 19 ×
*TODO chip hover affordance Projects · Jul 10
*TODO finish raskin ch. 4 Reading · Jul 9
*TODO ship lens spec Projects · Jul 11
+ Add… asks: → Projects or Reading?
+ one lens over both, written once
+ unified sort / group (interleaved)
add must ask where to home
one × closes both windows

Rule of thumb the UI teaches: reach for union exactly when you want one lens over both. The picker makes it cheap to choose either — then ![[ again for stacked, , for union — and converting later is a text edit.

njournal/2026-07-12 stacked = windows · union = a set
comma verdict:slugs exclude “,” like “:” — and the picker stores IDs, so display commas are cosmetic.

Where the state lives: the header lens joins day/week/month in per-page view state (something already remembers those); pin promotes it to a page property (lens: todo when:-3w.. — one grep-able line); name promotes it to lens/…, summonable via ![[. Stacking is intersection, and every hidden row can say which lens hid it. Union sources compose with lenses (![[Projects, Reading]]{todo}); relational join stays in Lua on purpose.