# The Companion You Earn

Author: Pramod Prasanth
Published: 2026-04-27
Canonical: https://pramod.ch/essays/the-companion-you-earn
Description: On Open Museum MCP, a frontmatter schema for paired-artwork blurbs, and a hybrid gate the reader has to earn. Three small projects that only get built when the writer holds the whole stack.

---

An essay I had just finished kept asking for an image. Not as decoration. Every blog post has those. As a second voice, arguing the same thing in a different medium. I didn't want a picture next to the text. I wanted something the reader would have to read past to deserve, and that I would have had to think hard to choose.

So I built three things that probably no product manager would have approved.

## What was wrong with just dropping in an image

The standard pattern is the path of least resistance: pick a stock photo, call it a hero, move on. Maybe credit the source. The picture is "decoration" in the strict sense. It is there because pages without images look bare, and absent any other constraint, that is the constraint that wins.

But decoration is the opposite of argument. A piece chosen to fill space carries the message *this image is interchangeable with any other image at this size*. The reader correctly registers it as low signal and doesn't look. Worse: as a writer, I haven't *committed* anything by choosing it. I haven't said "this artwork makes the same point my essay does in a different medium, and I will defend that pairing." I've said "I needed a picture and this one was free."

> Decoration is the opposite of argument.

That's a writing problem dressed as a layout problem.

## The infrastructure: Open Museum MCP

Public-domain museum collections are everywhere if you look. The Met opened theirs in 2017. Cleveland Museum of Art has tens of thousands of high-resolution CC0 works. The Art Institute of Chicago, the National Gallery of Art, Rijksmuseum, Smithsonian: all ship APIs, mostly with open licences on the works that are out of copyright.

The problem nobody has solved is *federation*. Each museum has a different schema, a different licence vocabulary, a different way of marking what's reusable. Most "free art" search tools silently mix in works where the image is licensed but the underlying object isn't, or vice versa. Licence verification ends up being somebody else's problem, which means it ends up being nobody's.

For a feature that puts an artwork next to an essay and asserts *the artist would not object* (which is what public-domain status means in practice), I needed something I could trust. If the source institution says CC0 and the image rights field supports it, the work is surfaced. Otherwise it isn't, even if the metadata is otherwise interesting. The whole point of the layer is the things it refuses to return.

The current shape is three museums live (The Metropolitan Museum of Art, the Cleveland Museum of Art, and the Art Institute of Chicago). Next is the Walters Art Museum for clean per-museum CC0, then Europeana and Wikimedia Commons / Wikidata for breadth and cross-institution discovery, then Asian and African collections beyond what those federations cover well. The geographic widening is not decoration. The editorial rule against back-to-back European pre-1900 pairings depends on the search layer actually being able to surface non-European work. The roadmap and the discipline are the same project.

I built it as a Model Context Protocol server because that is where I do this work, inside the same tool I am drafting in. `search_artworks query:"birds parable" limit:8` while I am staring at a paragraph that needs a companion. I get back ten candidates, each with a licence string I can read, a citation I can paste, a thumbnail I can see at a glance.

The MCP integration matters for one reason: it puts the museum collection *in the writing tool*, not in a separate browser tab. Tabs encourage tab-thinking. The companion has to be part of the same draft, not a side errand.

## The schema: three fields that force three different acts of attention

The frontmatter for a paired essay carries an `artwork` block with the standard metadata (title, artist, year, license, source URL) and three blurb fields:

```yaml
blurb:
  what: |
    <object identification: title, artist, medium, museum>
  why: |
    <two to four sentences making the connection between the artwork
     and the essay's argument>
  look_at: |
    <one or two sentences pointing at a specific visual detail the
     reader would otherwise skim past>
```

Three fields, deliberately, because each one demands a different kind of attention.

`what` is the cataloguing impulse, the boring true sentence about the object. It anchors the reader in what they are looking at.

`why` is the editorial argument. This is where it gets dangerous: it is easy to write something plausible and generic ("This piece resonates with the essay's themes of memory and loss"). The defence is that every blurb runs through a writing-quality-check before publishing. If the `why` reads like it could attach to any artwork at the same scale, it doesn't ship.

`look_at` is the killer field. It forces a specific visual detail. Not "the colours are striking", but *which colours, where, doing what*. If I find myself writing in generalities, that is the signal I have not actually spent time with the image. The blurb is unfit to publish, and I have to either look harder or pick a different work.

The fields are small. The discipline is large.

## The pairing rule

The schema only enforces shape. The editorial constraints are the actual discipline:

- **No artist appears more than twice** across the corpus.
- **No back-to-back European pre-1900 pairings.**

Both rules cost me something. I have read deep on Renaissance Italy and the Dutch Golden Age, so the gravitational default is to keep returning there. The two-artist limit forces a longer search. The geographic rule forces me to learn outside that comfort zone: Persian miniatures, Edo-period prints, Mughal court paintings.

Forcing functions only work when they cost. If the rule said "pair with whatever fits," the search would collapse to the easiest match every time, which would mean the same *kind* of match every time, which would mean the companion stops being a companion and starts being a tic.

> Forcing functions only work when they cost.

The first paired essay, Yukti V (*What Europe Had That Kerala Did Not*), is companioned with a 1600s Persian illumination of Attar's *Mantiq al-Tayr*: the parable in which thirty birds set out to find their king, and what assembles them into something that can be received is the act of going. The pairing carries the essay's argument in a different medium: a tradition that had the results, the proofs, and the material care, but stayed bound inside a single hand-painted book. The peacock's gold and silver feathers, every one laid in by hand, would have to be re-painted by another hand in another book in another decade. There is no press. *That* is the look_at: every feather a labour that does not propagate.

I would not have arrived at that pairing under a "pick whatever's free" rule. I arrived at it under a "no European pre-1900 again" rule.

## The hybrid gate

If the writer's discipline is constraint at one end, the reader's discipline is gating at the other. The companion artwork does not appear at the bottom of the essay as a click-here-for-image link. It is earned.

Two gates, combined with `min()`:

- A **time gate** starts at 30% of the essay's estimated reading time and is fully eligible at 85%.
- A **progress gate** starts at 35% of furthest-scroll-position-ever-reached and is fully eligible at 80%.

`reveal = min(timeGate, progressGate)`.

Either gate alone is gameable. Time alone fails to a reader who opens the tab and walks away. Progress alone fails to a five-second skim from top to bottom. The min() forces both to be true: the reader has to spend committed visible-tab time *and* actually move through the prose.

There is also a skip-protection layer. If the scroll position jumps more than 18% in under 1.25 seconds, the new position is held as a candidate, not promoted to "furthest ever reached" until the reader dwells near it for at least 2.5 seconds. It is not anti-cheat. Anyone determined enough can defeat a client-side gate. It is a forcing function on the reader: if you want to skim, you can, but the artwork will not pop. The reveal is part of finishing.

The visual layer cooperates. While the gate is incomplete, two blurred image strips form in the page gutters, gradually sharpening as the reveal value rises. A small "ready" pill appears in the top-right when both gates close. Clicking it scrolls down to the inline reveal: title, artist, year, blurb, attribution. Print and reduced-motion viewers see the artwork statically; mobile viewers see it the same way, since the gutter art only renders on screens wide enough to spare the side margins.

The reader earns the companion. The writer earns the right to ship it. The asymmetry is the point.

> The reader earns the companion. The writer earns the right to ship it. The asymmetry is the point.

## Why no PM would have signed off on any of this

Three things, each of which is a small project, none of which would survive a backlog. An MCP server that federates open-access museum collections (three live, more coming), when nobody has ever asked for one. A frontmatter schema with editorial-discipline fields nobody else would write to. A gating logic that *delays gratification on a personal blog*, measurably the wrong direction for engagement metrics.

Each one only makes sense if the writer is the same person as the engineer is the same person as the reader. In a normal product, decisions split across those roles, and the path of least resistance becomes "drop in a hero image, ship the post, move on." That is what the medium pulls toward by default.

The thing about working alone, really alone but with AI doing the work no single human could keep up with, is that you can build the discipline you actually want to practise, not the discipline a planning meeting allows. A constraint-shaped feature. A forcing-function-shaped tool. A small piece of infrastructure that exists only to make a particular flavour of work harder. These get built when the writer holds the whole stack.

The companion is not a feature on a website. It is a piece of writing infrastructure that pushes me to see images I would not otherwise look at, write blurbs I would not otherwise commit to, and ship pairings I would not otherwise dare. The reader's experience of "earning" the artwork is downstream of *my* having to earn the right to put it there.

## The source is open

The MCP server is on npm[^1] and the source is on GitHub[^2] under MIT. I wrote it for myself, but the architecture is built around per-museum adapters. Each museum's API is a separate file. Each one is small.

The hope is not that engineers contribute. It is that art-lovers do. Someone who has spent years walking through the Mathaf in Doha, or the Iziko in Cape Town, or the Asian Civilisations Museum in Singapore, knows what their collection holds in a way no general search ever will. If you have that kind of love for a collection and you also write code, the adapter is a weekend's work. The contribution is not the code. It is that the next person pairing an essay can reach into a collection that someone else wanted to be reachable.

The bet is small. What it makes possible is not.

I am not sure the discipline scales beyond me. I am sure I will not ship without it.

---

### Sources

[^1]: [open-museum-mcp on npm](https://www.npmjs.com/package/open-museum-mcp). License-verified search across open-access museum collections.

[^2]: [open-museum-mcp on GitHub](https://github.com/cfpramod/open-museum-mcp). MIT-licensed source. Per-museum adapters under `src/museums/`; PRs welcome.
