Skip to content

Serve every author as an OpenProfile.md, and let the person correct it - #191

Merged
ralyodio merged 1 commit into
mainfrom
feat/openprofile
Sep 13, 2026
Merged

Serve every author as an OpenProfile.md, and let the person correct it#191
ralyodio merged 1 commit into
mainfrom
feat/openprofile

Conversation

@ralyodio

Copy link
Copy Markdown
Contributor

Part of the OpenProfile rollout (Anthony, 2026-09-13: p0dcasters needs OpenProfiles from rssamplifier; anywhere OpenProfile is implemented the person can edit it via API, CLI, MCP, web).

Serve

  • GET /authors/{slug}/openprofile.md: the author as OpenProfile.md via @profullstack/openprofile. Identity (Kind, Handle, Web, Avatar), headline from the bio, Accounts from author_links, Topics from their feeds' keywords, a Broadcast section (OpenBroadcast) per show they own (### <show> groups when several) with Show, Kind, Language, Since, Feed, Listen, Topics only. Never Seeking/Pays/Charges/Guest, never Email unless the owner adds it.
  • <link rel="openprofile"> on /authors/{slug}, a Profile row with the file and a "this is me" button; openprofile URL in /api/authors, /api/authors/{slug}, /api/feeds/{slug}.authors, MCP get_author; llms.txt, skill.md, README.
  • GET /api/authors?feed={url}: the people behind one feed, owner first.
  • MCP get_openprofile (by slug or feed URL).

Claim and edit

  • Migration 20260913042000_author_profiles (overlay JSON, public switch, owner account and/or OpenAccess principal, claim method).
  • POST /api/authors/{slug}/claim: verified automatically by email equality with the published address, or by the site linking back with rel="openprofile"/rel="me" (fetched, 8s, 512 KB). Admin fallback via ADMIN_EMAILS. 401 / 403 / 409 as appropriate.
  • PUT /api/authors/{slug}/openprofile: text/markdown (whole file, dropped sections dropped) or JSON patch (name, headline, prose, identity, sections, public, or markdown). Auth: session cookie, an rsa_ API key, or an OpenAccess bearer with openprofile:edit (@logicsrc/openaccess; scope added to /.well-known/openaccess.json). POST is the same for the HTML form.
  • Web: /authors/{slug}/edit (one box per part, public checkbox); claimed profiles listed on /account.
  • CLI 0.4.0: rssamp profile <slug> / --feed <url>, profile claim <slug>, profile edit <slug> [--file] (opens $EDITOR, sends only if changed); --token, RSSAMPLIFIER_TOKEN, OPENACCESS_TOKEN.
  • MCP update_openprofile, claim_openprofile (credential in the Authorization header); listed in openmcp.json.

Fix on the way: authorBySlug read the legacy feeds.kind (always blog); it now reads category under that name, so the author page and get_author say podcast for a podcast.

Tests: packages/db/test/profiles.test.js, apps/web/test/openprofile.test.js (generator, overlay round trip, form, claim verdicts, linkback, OpenAccess principal), apps/cli/test/profile.test.js; pnpm test green. Smoke against a local file database with a seeded author: the file, the JSON shape, ?feed= lookup, the link rel, 401s, claim by email under an API key, PUT patch, MCP get/update, public off then 404.

🤖 Generated with Claude Code

https://claude.ai/code/session_01S7yeJUHGxA4P5N74xnsRPQ

The directory already knew who is behind a feed, from the markup they
published: a rel="me" link, an h-card, the feed's own author element.
That knowledge now leaves the site as one portable file per person,
/authors/{slug}/openprofile.md (logicsrc.com/openprofile), pointed at by
<link rel="openprofile"> on their page: identity block, Accounts, Topics
from their feeds, and a Broadcast section (logicsrc.com/openbroadcast)
for every podcast or show they own, saying only what their own feed
says. Nothing the person did not write is filled in: no Seeking, Pays or
Charges, no Guest section, and no email even where the API republishes
one. GET /api/authors?feed={url} finds the people behind a feed, so a
directory that holds only feed URLs can reach them.

Then the person's word over ours. A claim is verified on the spot: the
signed-in address is the one they published, or their site links back at
the profile. After that the file is theirs to correct from anywhere, and
every way in stores the same overlay (@profullstack/openprofile): the
edit form at /authors/{slug}/edit, PUT /api/authors/{slug}/openprofile
as the whole file or a JSON patch under an API key or an OpenAccess grant
for openprofile:edit, rssamp profile edit from the CLI, update_openprofile
over MCP. What they wrote wins per section, what they left alone is still
generated, and `none` drops a section. A public switch hides the file
without touching the page.

Also: authorBySlug now reads the live `category` under the `kind` name,
which the author page and get_author already expected; the old column
said blog for every podcast.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S7yeJUHGxA4P5N74xnsRPQ
@socket-security

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Added@​logicsrc/​openaccess@​0.3.0771009390100

View full report

@ralyodio
ralyodio merged commit a375fa4 into main Sep 13, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant