---
title: "Feed lenses: how Open Media orders the Feed"
description: "Raw, Relevant and every shared feed algorithm are small JSON manifests run by one open-source runner. The format, the built-in lenses, and how agents write, preview, save and share one."
canonical: https://openmedia.site/docs/feed-lenses
last-updated: 2026-10-27
---

# Feed lenses

Every way of ordering the Open Media Feed is a **lens**: a small JSON manifest, never code. Raw, Relevant and Work are built in; Work is the professional feed of jobs, hiring and networking (ADR 0018). People can describe a new lens in plain words in Search, or ask an AI agent to write one, then keep it, share it publicly, or install someone else's.

One open-source runner orders the posts: [src/domain/feedLenses.ts](https://github.com/mihirkavi/open-media/blob/main/src/domain/feedLenses.ts). The app, the REST API and the MCP servers all use it, so an agent's preview matches the person's Feed. The design is [ADR 0017](https://github.com/mihirkavi/open-media/blob/main/docs/adrs/0017-feed-lenses.md); tuning, boosts and versions are [ADR 0021](https://github.com/mihirkavi/open-media/blob/main/docs/adrs/0021-your-own-feed-algorithm.md).

## The built-in lenses

### Relevant

Newer posts first, lifted when you follow the author or a post matches a topic you chose, with authors and networks spread out. Nothing else is used.

- Ranked by newness 50%, who you follow 30%, your topics 20%
- Spreads authors and networks out

```json
{
  "format": "open-media.feed-lens/1",
  "id": "relevant",
  "name": "Relevant",
  "version": 2,
  "builtIn": true,
  "author": "Open Media",
  "description": "Newer posts first, lifted when you follow the author or a post matches a topic you chose, with authors and networks spread out. Nothing else is used.",
  "permissions": [
    "follows",
    "interests"
  ],
  "filters": {},
  "order": "ranked",
  "objectives": {
    "recency": 0.5,
    "follows": 0.3,
    "interests": 0.2,
    "engagement": 0,
    "diversity": 0.3
  },
  "interests": []
}
```

### Raw

Every eligible post, newest first. Nothing is ranked or hidden by the lens. Raw is always available.

- Newest first

```json
{
  "format": "open-media.feed-lens/1",
  "id": "raw",
  "name": "Raw",
  "version": 1,
  "builtIn": true,
  "author": "Open Media",
  "description": "Every eligible post, newest first. Nothing is ranked or hidden by the lens. Raw is always available.",
  "permissions": [],
  "filters": {},
  "order": "newest",
  "objectives": {
    "recency": 1,
    "follows": 0,
    "interests": 0,
    "engagement": 0,
    "diversity": 0
  },
  "interests": []
}
```

### Work

Jobs, hiring, careers, launches and professional events, newer first and lifted when you follow the author or a post matches a topic you chose. Nothing else is used.

- About job, jobs, hiring, hire, career, careers, role, resume, interview, internship, recruiting, networking, startup, founder, conference, launch, launched, opentowork, remote, freelance
- Ranked by newness 45%, who you follow 32%, your topics 23%
- Spreads authors and networks out

```json
{
  "format": "open-media.feed-lens/1",
  "id": "work",
  "name": "Work",
  "version": 1,
  "builtIn": true,
  "author": "Open Media",
  "description": "Jobs, hiring, careers, launches and professional events, newer first and lifted when you follow the author or a post matches a topic you chose. Nothing else is used.",
  "permissions": [
    "follows",
    "interests"
  ],
  "filters": {
    "about": [
      "job",
      "jobs",
      "hiring",
      "hire",
      "career",
      "careers",
      "role",
      "resume",
      "interview",
      "internship",
      "recruiting",
      "networking",
      "startup",
      "founder",
      "conference",
      "launch",
      "launched",
      "opentowork",
      "remote",
      "freelance"
    ]
  },
  "order": "ranked",
  "objectives": {
    "recency": 0.5,
    "follows": 0.35,
    "interests": 0.25,
    "engagement": 0,
    "diversity": 0.3
  },
  "interests": []
}
```

Relevant's recency counts half as much every 12 hours, so older posts still appear in time order rather than all at the bottom.

## What a lens can and cannot read

- Always: each post's text, time, network and kind (video, image, product, service, event).
- Only when its manifest lists the permission: `follows` (who the person follows on Open Media), `interests` (topics the person or the lens chose), `public_engagement` (like and repost counts a network publishes).
- Never, for any lens: Private messages, Exact location, Sensitive-trait inference, KYC documents, Emotional-state prediction. These cannot be written in a manifest; unknown fields are refused.

## Writing a lens

```json
{
  "format": "open-media.feed-lens/1",
  "name": "Cooking videos",
  "permissions": ["follows"],
  "filters": { "kinds": ["video"], "about": ["cooking"], "mute": ["crypto"], "hideSources": ["hive"] },
  "order": "ranked",
  "objectives": { "recency": 0.6, "follows": 0.4, "interests": 0, "engagement": 0, "diversity": 0.3 },
  "interests": []
}
```

Fields: `filters` keep posts (`sources`, `kinds`, `about`, `followedOnly`, `maxAgeHours`) and leave them out (`hideSources`, `hideKinds`, `mute`, `muteAuthors`). `order` is `newest` or `ranked`. `objectives` weigh recency, follows, interests, engagement and discovery (normalized), and `diversity` spreads authors out. The full field list is in `GET https://openmedia.site/v1/lenses`.

## Your own algorithm: boosts, tuning and versions

Format `open-media.feed-lens/2` adds two things. A lens that uses neither is still written as `open-media.feed-lens/1`.

- `boosts`: up to 24 leanings toward or away from one network, kind, topic or person, without hiding anything. Each is `{ "source" | "kind" | "topic" | "author": …, "weight": -1 to 1 }`, and a matching post's score is multiplied by 1 + weight/2. All of a post's boosts together stay between ×0.25 and ×2.
- `objectives.discovery`: lifts authors the person does not follow yet. Needs `follows`.

```json
{
  "format": "open-media.feed-lens/2",
  "id": "my-relevant",
  "name": "My Relevant",
  "version": 2,
  "description": "Your own copy of Relevant, tuned in your own words.",
  "permissions": [
    "follows",
    "interests"
  ],
  "filters": {},
  "order": "ranked",
  "objectives": {
    "recency": 0.5,
    "follows": 0.3,
    "interests": 0.2,
    "engagement": 0,
    "diversity": 0.3
  },
  "interests": [],
  "boosts": [
    {
      "weight": -0.5,
      "source": "hive"
    },
    {
      "weight": 0.5,
      "kind": "video"
    },
    {
      "weight": 1,
      "topic": "design"
    }
  ],
  "forkedFrom": "relevant"
}
```

People tune the lens they use in plain words: "less hive", "a lot more videos", "more about design", "a bit less from @bot", "more from people I follow", "more new voices", "mute crypto", "show hive again", "chronological". Tuning Raw, Relevant or Work makes the person's own copy ("My Relevant"); the built-ins never change. The person's account numbers every change, keeps the last 50 versions with whether the person or an agent made them, and can go back. Anyone can audit how a shared lens changed while it was shared. Installed copies never change when the author changes the original.

"Why this?" shows each post's score under the lens's own weights: points per objective, and each boost that matched with its multiplier.

## For agents

Public, no key (`https://openmedia.site/open/mcp` or REST):

- `list_feed_lenses` / `GET https://openmedia.site/v1/lenses?q=`: the built-in and shared lenses, with rules in words.
- `get_feed_lens` / `GET https://openmedia.site/v1/lenses/{id}`.
- `draft_feed_lens` / `POST https://openmedia.site/v1/lenses/draft` `{"request": "only videos about cooking, no crypto"}`: plain words to a manifest, with what was and was not understood.
- `preview_feed_lens` / `POST https://openmedia.site/v1/lenses/preview` `{"lens": {…}}` or `{"request": "…"}`: the public Feed through that lens, each post with its "why".
- `get_feed` with `lens` / `GET https://openmedia.site/v1/feed?lens=relevant`.
- `draft_feed_lens` with `base` / `POST https://openmedia.site/v1/lenses/draft` `{"base": "relevant", "request": "less hive, more videos"}`: the change, the rules that changed, nothing saved.
- `get_feed_lens_history` / `GET https://openmedia.site/v1/lenses/{id}/history`: how a shared lens changed.

The person's account (`https://openmedia.site/me/mcp`, bearer token):

- `list_my_feed_lenses`, `save_feed_lens` (`visibility`: private or public), `install_feed_lens` (copy a shared lens), `delete_feed_lens`, and `get_my_feed` (the Feed through a lens with the person's follows; each post's `why.scoring` shows its score).
- `tune_feed_lens` / `POST https://openmedia.site/v1/me/lenses/{key}/tune` `{"request": "less hive"}` (`save: false` previews), `get_my_feed_lens_history` / `GET https://openmedia.site/v1/me/lenses/{key}/history`, and `revert_feed_lens` / `POST https://openmedia.site/v1/me/lenses/{key}/revert` `{"version": 2}`. Changes made here are recorded as made by an agent.

Show the person a lens's summary and rules before saving it, and ask before sharing it publicly. A saved lens appears in the person's Feed picker on every device; a shared one opens for anyone at `https://openmedia.site/?lens=%3Cid%3E`.

## In the app

There is no lens editor. People write what they want in Search ("only videos from people I follow, no crypto"); Search shows the lens it understood, and choosing it switches the Feed. Words like "less hive" or "more videos" show "Tune 'My Relevant': …" for the lens in use, and "undo" lists earlier versions. The Feed's picker shows Relevant, Raw and the lens in use. "Why this?" on every post lists the signals used, the lens's rules, the post's score under those rules, and what was never used.
