Feeds — Quickstart
Declare a feed, push, render with useFeed. Five moves, no ingest re-run
needed if you already have vectors.
feed articles
Config Explorer Call Result
json editor
articles : {
source : 'main' ,
table : 'articles' ,
fields : {
id : { type : 'number' , primaryKey : true },
title : { type : 'text' , searchable : { weight : 2 } },
body : { type : 'text' , searchable : true },
tags : { type : 'text' },
updated_at : { type : 'date' },
},
feeds : {
foryou : {
candidates : { from : 'embeddings' , limit : 300 },
rank : {
similarity : { weight : 0.7 , against : 'topics' },
recency : { weight : 0.3 , halfLife : '7d' },
},
pagination : { pageSize : 10 },
},
},
grants : {
feed : { foryou : 'public' },
},
}
Open sl.config.ts. Declare the feed under feeds.<name>, then grant it
access under grants.feed.<name>. The smallest useful feed has
candidates.from, a rank block, and an access rule:
Copy
articles : {
feeds : {
foryou : {
candidates : { from : 'embeddings' , limit : 300 },
rank : {
similarity : { weight : 0.7 , against : 'topics' },
recency : { weight : 0.3 , halfLife : '7d' },
},
pagination : { pageSize : 10 },
},
},
grants : {
feed : { foryou : 'public' },
},
}
This registers the new feed without re-ingesting. Feeds read from the same
vectors the search operation uses — so if your lens already has searchable
fields indexed, you're ready.
Copy
semilayer feed list articles
semilayer feed view articles.foryou --context '{"topics":["security"]}'
Beam emits a feed namespace on each lens. Every declared feed gets a typed
method with a matching .next(), .subscribe(), and .explain():
Copy
import { beam } from './beam'
const page = await beam.articles .feed .foryou ({
context : { topics : ['security' , 'auth' ] },
pageSize : 10 ,
})
Copy
import { useFeed } from '@semilayer/react'
import { beam } from '@/lib/beam'
const feed = beam.articles .feed .foryou
export function ForYouFeed ( ) {
const { items, fetchMore, cursor, isLoading } = useFeed (feed, {
context : { topics : ['security' , 'auth' ] },
liveUpdates : true ,
pageSize : 10 ,
})
return (
<div >
{items.map((it) => (
<article key ={it.id} >
<h3 > {it.metadata.title}</h3 >
<small > rank #{it.rank} · score {it.score.toFixed(2)}</small >
</article >
))}
{cursor && <button onClick ={fetchMore} disabled ={isLoading} > Load more</button > }
</div >
)
}
Done. items[i].metadata is fully typed from the lens's field declarations.
A typed Beam method: beam.articles.feed.foryou(params)
A WebSocket subscription: feed.foryou.subscribe() yields feed.tick events
A debug endpoint: feed.foryou.explain({ recordId }) (sk-only)
A React hook integration that owns pagination + evolution
All from one config block. Next up: Ranking — every scorer
with worked math.