Oct 29
notefeed 0.34.0
Released 2026-10-29 · on GitHub
The operator can take down one post instead of the whole feed (#159, ADR 0052). With
"scope": "note",POST /api/operator/takedowntakes a note's read URL, an image URL or<read id>/<note id>(what a report carries). It removes the post: the note, the text it was posted with, and every picture posted with that text. Their images go on the blocklist, as with a feed takedown. In the post's place, the feed shows a mark: "Removed by the operator: this broke the content rules of this instance.", linked to the terms page when there is one. Whoever can post to the feed can delete the mark, but the post does not come back. The removed notes answer 410 (removed) in the API, MCP and their file links, also once the mark is deleted. Readers only learn of removals they could have seen: a removed draft, or a removed post dated later, is a missing note to them. Withoutscope, the takedown removes the whole feed, as before.In the APIs and clients the mark is a note with
removed: trueand the typeapplication/x-notefeed-removed. It has the removed note's id and date and no content. Getting or editing it answers 410 (removed), and deleting it works like for any note.Every note now counts against a feed's limits: texts, pictures and marks alike. On a free feed, the newest notes kept include pictures kept from a license that ran out, and the oldest note to go may be a picture or a mark.
NOTEFEED_MAX_NOTES_PER_FEEDcounts every note too;NOTEFEED_MAX_IMAGES_PER_FEEDstill limits pictures on their own. Takedowns of posts are counted innotefeed_notes_deleted_totalwithreason="takedown".Breaking:
NOTEFEED_MAX_NOTES_PER_FEEDcounted only text notes and now counts pictures as well. On an instance that sets it, a feed with many pictures reaches the limit sooner and further posts answer 507 (note_limit). Raise the value if that matters to you. A free feed's cap counts pictures too: a feed that kept pictures after its license ran out drops its oldest notes sooner.Upgrading: on SQLite and PostgreSQL the first start adds a table (migration
008_note_tombstones); take a backup first. No setting changes.MCP:
list_notesandget_notemark the operator's marks withremoved: true;get_noteandedit_noterefuse a removed note, anddelete_notedeletes a mark. Assistants see this after reconnecting (Claude: a new chat, or remove and add the connector; Claude Code: restart).
Oct 28
notefeed 0.33.1
Released 2026-10-28 · on GitHub
Drafts and scheduled notes no longer show a Report link (#327). No reader can see them, so there is nothing to report, and the operator could not open them from a report; whoever sees one can remove it. A note gets its Report link once readers see it. On notefeed.me the terms, privacy page and imprint say the link is on every published note.
Upgrading: nothing to do.
notefeed 0.33.0
Released 2026-10-28 · on GitHub
A note can be a draft (#265, ADR 0051). Whoever can post to the feed sees it on the feed page, marked as a draft, and edits it like any note; readers don't see it anywhere: not on the read link, in RSS or in the read API, and its address and its pictures' files answer 404. Publishing it changes nothing else: it keeps its id, its links and its date, so a draft dated in the past takes its place there and one dated in the future becomes a scheduled note. A published note can be made a draft again. Pictures posted with a note follow it. A draft picture can't be the feed's title image, and a note whose picture is the title image can't become a draft. In the web UI it is the Draft box in the compose box and in a note's edit form; in the API
X-Note-Draft: trueon a post anddraftin a PATCH; in the clientsdraftwhen posting and updating, andnotefeed post --draft,notefeed update --draft/--publish.The post-to-notefeed skill asks where your drafts live: in the conversation, on the feed itself, or in a second feed whose read link you can send to a reviewer.
The report form asks for what the EU's Digital Services Act says a notice holds (Art. 16(2)): an optional name beside the optional e-mail address, and a box to confirm you report in good faith (#319).
Upgrading: on SQLite and PostgreSQL the first start adds a column to the notes table and rebuilds its index (migration
007_note_draft); take a backup first. WithNOTEFEED_REPORT_ENDPOINTset, the report page now also postsnameandgood_faith(Yes): an inbox that refuses unknown fields needs them before the upgrade. notefeed.me's inbox has them.MCP:
post_note,post_fileandedit_notetakedraft;list_notesandget_notemark drafts withdraft: true. Assistants see them after reconnecting (Claude: a new chat, or remove and add the connector; Claude Code: restart).notefeed 0.32.0
Released 2026-10-28 · on GitHub
A license key no longer opens the payment provider's customer portal. That portal shows the buyer's e-mail address, payment method and invoices, and every license they bought with its key, so one key handed to a co-author or put into a script could reach the buyer's data and their other feeds (#316, ADR 0050). Buyers now manage their purchases at Creem themselves: sign in at https://creem.io/my-orders/login with the e-mail address you bought with, or use the link in the receipt. The license page links there under "Manage your purchases".
Scripts and agents can ask what licenses are sold, where to buy one and where buyers manage them:
GET /api/v1/licenses, the MCP toolget_licenses, andlicenses()in both client packages.Upgrading: nothing to do.
MCP: a new tool,
get_licenses. Assistants see it after reconnecting (Claude: a new chat, or remove and add the connector; Claude Code: restart).notefeed 0.31.1
Released 2026-10-28 · on GitHub
The page that says what notefeed stands for has moved to https://docs.notefeed.me/values/ (it was /vision/ for a few hours). The footer's "Values" link and the start page point there.
Upgrading: nothing to do.
notefeed 0.31.0
Released 2026-10-28 · on GitHub
Pictures can be shared to notefeed from the phone. On Android, notefeed installed from Chrome takes pictures, text and links from the share sheet: pick a feed and they wait in its compose box until you post (Samsung Internet's installed app does not yet, #314). On the iPhone, a Shortcut does the same; the new docs page "Sharing from a phone" has the recipe. Pictures in one post may now share a file name, unless the text refers to it.
Every image is now shrunk, turned upright and stripped of its metadata (location, camera) on the server, whatever posted it: the web page, a script, the clients or an assistant over MCP. It is stored at most 2560 px wide or high, in its own format; animations stay. An upload may be up to 10 MiB (was 5), so a phone photo goes as it is (ADR 0049).
A title image uploaded in the feed's settings is the feed's own and no longer shows up as a post:
PUT/DELETE /api/v1/feeds/{feed}/image, MCPset_feed_image, andsetFeedImage/removeFeedImage(JS),set_feed_image/remove_feed_image(Python). Title images uploaded before stay posts until set again.The version an instance runs is shown in the footer and the ⓘ menu, and
/healthsays it. A note's page shows the feed with a large "All notes" beside it on a wide screen, and pictures in a note are kept to a sensible size.notefeed has a page that says what it stands for: no accounts, no personal data, publishing rather than interacting, and what follows from that (https://docs.notefeed.me/vision/). Every page links to it from the footer ("Values").
Breaking: a file that only starts like an image but is none is now refused with
415, an image over 100 megapixels with413. When the server is busy processing images it answers503withRetry-After, which both clients raise asRateLimitedError.Upgrading:
NOTEFEED_SHRINK_IMAGE_BYTESis gone (the browser no longer shrinks pictures; the server does); a start with it set logs a warning.NOTEFEED_MAX_IMAGE_BYTESnow defaults to 10 MiB, which is also its most. notefeed.me sets neither.MCP: a new tool,
set_feed_image;post_note's pictures may share a name unless the markdown refers to it. Assistants see the new tool after reconnecting (Claude: a new chat, or remove and add the connector; Claude Code: restart).
Oct 27
notefeed 0.30.0
Released 2026-10-27 · on GitHub
A feed can be created without posting a note, to reserve its name with a password, a license and a read id:
POST /api/v1/feeds/{feed}, MCPcreate_feed,createFeed/create_feedin the clients, or "Create feed without a note" in a new feed's card. Where licenses are sold it needs a license key, which goes on the new feed (ADR 0047).A lost feed password can be reset with the feed's license key from scripts and agents too:
POST /api/v1/feeds/{feed}/password/recover, MCPrecover_feed_password,recoverFeedPassword/recover_feed_passwordin the clients. In the web UI, a browser that is still unlocked finds the same under "Forgot the current password?" in the feed's settings. Changing a password now says so next to the password row ("Password changed."), instead of a small "Saved." at the top of the page.Feeds with an active license are no longer rate limited on posts, edits and deletes; wrong passwords and keys still are (ADR 0046).
The page uses the whole width of the window. Mermaid diagrams are drawn in the feed's timeline too, and a click opens one enlarged.
Each release now posts the agent skills to notefeed.me's
skillsfeed:curl -O https://notefeed.me/r/skills/post-to-notefeed.mdalways gets the newest.Upgrading: nothing to do. notefeed.me reserves the new
skillsfeed in notefeed-ansible (NOTEFEED_RESERVED_FEEDS).MCP: two new tools,
create_feedandrecover_feed_password. Assistants see them after reconnecting (Claude: a new chat, or remove and add the connector; Claude Code: restart).notefeed 0.29.0
Released 2026-10-27 · on GitHub
Tags can be changed after posting: the edit form,
PATCHwithtags, MCPedit_noteandnotefeed update --tagsin both clients. Tags that are numbers sort as numbers.An open feed can be claimed by setting a password (ADR 0044): whoever has the feed's name may set the first one, on the settings page, with
PUT /api/v1/feeds/{feed}/password, MCPupdate_feed new_passwordor the clients. A license can go on a feed without a password, when the feed is created or later (ADR 0043). Where licenses are sold, a lapsed key is now refused with402, and an unknown key counts against the per-IP limit like a wrong password.Long notes read better: heading anchors, a table of contents from three headings on, picture sizes (
), code highlighting on the page and in RSS, and Mermaid diagrams. A note posted with a name (X-Note-Name, MCPpost_note name) is served by that name under the read link:/r/<read id>/<name>(ADR 0045).For operators: the footer links only the feeds in
NOTEFEED_FOOTER_FEEDS, in that order; unset, it links none (it used to link every reserved feed). Reserved feeds no longer hit the free tier's limits. Euro prices show as1.99 €.Dependencies: Next.js 16.4.3, the MCP server 2.3.1 and zod 4.6.7 with security fixes.
Breaking: where licenses are sold, a lapsed license key is refused with
402when attached or used to create a feed; it used to be accepted and did nothing. An unknown key now counts against the per-IP limit like a wrong password.Upgrading: the footer links only the feeds in
NOTEFEED_FOOTER_FEEDS, in that order. Unset, it links none; it used to link every reserved feed.MCP:
post_notetakesname;edit_notetakestags;update_feedtakeslicense_keyandnew_password, and its title and description are optional. Assistants see the new parameters only after reconnecting: in Claude, start a new chat (or remove and add the notefeed connector); restart Claude Code.
Oct 26
notefeed 0.28.0
Released 2026-10-26 · on GitHub
A note's date is its own now, no longer part of its id (ADR 0042). A note posted with a date in the future is scheduled: readers see it only from that time on, on the read page, in RSS and in the read API. Its owner sees it marked as scheduled. A note's date can be changed at any time:
PATCHwithdate, the MCP tooledit_note,notefeed update --datein both clients, or the edit form on the note's page. Images posted with a text move with it.Breaking: the time of a post is
X-Note-Date(wasX-Note-Created, which is now refused with a 400), anddateeverywhere else (wascreated_atin MCP and Python,createdAtin JS,--createdin the CLIs). There is no alias.Note ids are random now. On its first start, 0.28.0 gives every existing note a new id and keeps its date. Links to single notes and files with the old ids stop working, and links from one feed to another are not rewritten. Back up the data and the images before upgrading.
- #246: Opaque note ids, scheduled notes, changing a note's date (ADR 0042)
notefeed 0.27.0
Released 2026-10-26 · on GitHub
A note can be posted with a time other than now:
X-Note-Createdon a post takes an ISO 8601 date-time with its offset, or a date alone, from 1970 up to now. The note's id and time come from it, so the feed, its read link and RSS place it there. The MCP toolpost_notetakescreated_at, the JS clientcreatedAtandnotefeed post --created, the Python clientcreated_atand--created, and the compose box has a date-and-time field next to Tags.The footer and the ⓘ menu link to notefeed's own feeds: the release notes and the blog.
- #237: Footer and ⓘ menu link to the reserved feeds
- #239: Post a note with a time other than now (X-Note-Created)
Oct 25
notefeed 0.26.0
Released 2026-10-25 · on GitHub
A note shows its text as written, in the list and on its own page (ADR 0040): only a title of its own, set when posting or editing, is a heading above it, and no line of the text is dropped for a guessed title any more. A click anywhere on a note's card opens the note; its time is the link itself. The "Notes tagged" line above a filtered list is gone: the feed's tags show which one filters.
In RSS, an item's description is the note's text as HTML, rendered as the page renders it, so readers show pictures instead of markdown (ADR 0041). The first picture of a note is the item's image (Media RSS), and a picture without a title is titled by its alternative text, its file's name, or "Picture" and its time, never its id.
- #232: Notes show their text as written; a click anywhere on a card opens it (ADR 0040)
- #234: RSS: descriptions are HTML, the first picture is the item's image, no ids as titles (ADR 0041)
notefeed 0.25.0
Released 2026-10-25 · on GitHub
The operator gets usage on /metrics (ADR 0039): how many feeds, notes, images and bytes the instance holds, how many feeds were active in the last day, week and month, how many free feeds are near or at the note cap, the licenses by state, and on a database its size (and on PostgreSQL its connections). Counted at most every five minutes, never per scrape. Next to them, counters for feeds created and removed, notes posted, edited and deleted, and license events. No metric names a feed, a read id or a key, and none is per feed.
Every kind of note follows one rule for clicks (ADR 0038): in a list, everything on a note's card opens the note; on a note's own page, a picture opens the picture's own page.
- #229: Feed: a note's picture opens the note first, then the picture's own note
- #230: UI: note kinds in one registry, one click rule for every kind
- #231: Metrics: usage gauges and event counters for the operator
Oct 24
notefeed 0.24.0
Released 2026-10-24 · on GitHub
A picture posted with a markdown note shows once: inside the note, no longer again as a note of its own in the feed, the read-only view and RSS. Clicking it opens the picture's own page, from the feed and from the note's page. A picture is only left out of a list that also holds the note showing it, so a tag filter that lists the picture alone still shows it; the API lists every note as before.
On an instance that sells licenses, the license page's tiles line up: prices, features and buttons sit at the same height whatever the plans' names and badges, and the free tile's price gets the plans' currency ("€0").
- #227: License page: the tiles line up (#223)
- #228: A note's pictures show once: inside the note, linking to their own pages
notefeed 0.23.1
Released 2026-10-24 · on GitHub
Deleting a note now asks in a dialog at every screen width. On wide screens the question used to appear as a card under the note, out of sight below a tall picture or a long note. The page is dimmed, Escape or a click beside the dialog cancels, and Cancel has the focus, so a stray Enter deletes nothing. Editing a note is unchanged.
- #226: Note page: delete asks in a dialog
Oct 21
notefeed 0.23.0
Released 2026-10-21 · on GitHub
On an instance that sells licenses, a lost feed password is recovered with the feed's license key: the unlock screen of a protected feed has "Forgot the password?", where the key attached to the feed and a new password set it anew (an active license is needed, like for any change), or an empty new password removes it (a lapsed license's key may do that too). A wrong key counts as a wrong password. The key, which the payment provider puts in the buyer's receipt and portal, is the proof of owning the feed; the password stays the secret to share. Instances without a payment provider show nothing new; the docs now describe how the operator removes a lost password with the SQL storage too.
- #225: A lost feed password is recovered with the feed's license key (ADR 0037)
notefeed 0.22.1
Released 2026-10-21 · on GitHub
A protected feed's settings page can enter a license key again: it posted to /api/licenses/attach, where the feed's unlock cookie is never sent, and was refused. It now posts and deletes under /<feed>/license. A new key also replaces a lapsed (refunded or run-out) license on the feed instead of being refused until the old one is detached.
- #224: License: a protected feed's settings page can enter a key again; a new key replaces a lapsed one
notefeed 0.22.0
Released 2026-10-21 · on GitHub
License keys now come from the payment provider: Creem issues the key, and it is also in the buyer's receipt e-mail and Creem's customer portal, so a lost key can be found again. notefeed still stores only its hash. After paying, the buyer comes back to /license?checkout_id=…, and the page asks the new POST /api/licenses/key for the key bought in that checkout. Each Creem product needs Creem's license key delivery; a completed checkout without a key is rejected. The license page shows an optional fine print below the tiles (fineprint in the operator's license.md), and the plan tiles no longer show the product's description, which is left to the provider's checkout. Self-hosted instances without a payment provider need no change.
- #222: License keys from Creem; license page: fine print, short tiles (#218)
notefeed 0.21.0
Released 2026-10-21 · on GitHub
A late subscription.expired or subscription.unpaid from the payment provider no longer lapses a license that has already been renewed past that period: an ending now carries the period it ends, and only ends the license if no later period was paid. Creem's renewal, a cancel at the period's end (which Creem carries out hours before that end, as a plain subscription.canceled) and a pause are tested against the deliveries of a sandbox run. Instances without a payment provider need no change.
- #221: A late subscription.expired does not lapse a renewed license; the daily sandbox run as a test (#218)
Oct 19
notefeed 0.20.0
Released 2026-10-19 · on GitHub
The license page of an instance that sells licenses now takes its words from the operator: a Markdown file with YAML front matter named by NOTEFEED_LICENSE_FILE holds the intro, the free tile and what every plan tile shows, and notefeed does not serve without it while a payment provider is set. Each plan's name, description and price are read from the configured Creem products and kept for five minutes, so a change in Creem shows without a deploy, and the yearly discount is computed from the two amounts. NOTEFEED_LICENSE_PRICE and NOTEFEED_LICENSE_PRICE_YEARLY are no longer read. Every instance can show a Support link in its footer with NOTEFEED_SUPPORT_EMAIL. Self-hosted instances without a payment provider need no change.
- #220: License page: words from license.md, plans from Creem's products; a Support link (#218)
Oct 18
notefeed 0.19.0
Released 2026-10-18 · on GitHub
Encryption at rest on the database backends: with NOTEFEED_ENCRYPTION_KEY, or with the main key in OpenBao (NOTEFEED_KMS=openbao), notefeed encrypts every feed's notes, images, metadata, settings and password with a data key of its own before they reach the database or the image store, and stores names and read ids only as fingerprints. A copy of the database, a dump or a bucket shows neither the notes nor a way into a feed. With OpenBao the main key never reaches notefeed, every unwrap is in OpenBao's audit log, and an unreachable OpenBao is a maintenance page (503 with the code unavailable from the API) rather than an error. A note that can't be decrypted is listed as a damaged note in its place instead of breaking its feed, and notefeed's own pages replace Next's plain not-found and error pages.
- #211: Settings: the REST API first under Posting
- #214: CLAUDE.md: commands, architecture and the production repos
- #216: Encryption at rest: envelope encryption on the database backends (#212)
- #217: Key service: the main key in OpenBao (#215)
Oct 17
notefeed 0.18.0
Released 2026-10-17 · on GitHub
A new feed's password and license key sit in a "Protect this feed" section next to the feed, not under the compose box. The license page shows a tile per plan, with what the yearly one saves, and the start page warns plainly that a feed's name is its key. The settings are in a clearer order, with a Posting section for scripts, AI agents over MCP, the client libraries and the REST API, each with its docs. On a phone the page fits the screen, and the note bar has a camera button. A creation that lost a race to a feed deleted at the same moment no longer leaves the name listed without its directory.
- #199: NOTEFEED #198: Two doors into the docs, notefeed.me and your own server
- #201: NOTEFEED #200: Trim the docs to the necessary content
- #204: NOTEFEED #202 #203: Phone page fits the screen; camera button in the note bar
- #206: NOTEFEED #205: Feed password and license key in the sidebar
- #207: Mention MCP as a way to post
- #208: License page: a tile per plan; a prominent warning about the feed's name
- #209: Settings in a clearer order; note page aligned with the feed page
- #210: A creation that lost to a feed deleted meanwhile no longer lists the name
Oct 16
notefeed 0.17.0
Released 2026-10-16 · on GitHub
A protected feed can be created on notefeed.me: the first note takes the license key next to the password, in the web UI, the API, the clients and MCP. A post refused for the lack of a license gets a banner that says what to do. The docs keep the hosted service's free tier and licenses on their own pages.
- #196: NOTEFEED #193: Create a protected feed with its license key in one post
- #197: Docs: keep the hosted service's free tier and licenses on their own pages
notefeed 0.16.0
Released 2026-10-16 · on GitHub
A yearly license next to the monthly one.
- #194: NOTEFEED #42: Sell a yearly license next to the monthly one
Oct 15
notefeed 0.15.0
Released 2026-10-15 · on GitHub
v0.15.0: a free feed shows its notes against the cap
Nothing to do when upgrading. Only instances that sell licenses (
NOTEFEED_PAYMENT_PROVIDERset) see a change; self-hosted instances without one are as before.Web UI
- Free tier usage: on an instance that sells licenses, the License row in a feed's settings reads "Free tier · N of 1000 notes" with a usage bar. The feed's page warns from 90 % of the cap and, at the cap, says that each new note drops the oldest one, with a link to the license page. Shown to whoever can post, never in RSS or on the read pages (#183).
API and clients
GET /api/v1/feeds/{feed}and the MCP server's feed tools returnfree_tier: { notes, cap }, ornullfor a licensed feed or an instance that sells no licenses. The JS and Python clients carry the new field.
Docs
- ADR 0031: configuration stays in environment variables (#189).
- ADR 0032: notefeed stays outside the EU Cyber Resilience Act, and the four facts that keep it there (#42).
Pull requests
- #190 ADR 0031, configuration stays in environment variables
- #191 Show a free feed's notes against the cap, and say so on the feed near it
- #192 ADR 0032, notefeed stays outside the Cyber Resilience Act
Oct 14
notefeed 0.14.0
Released 2026-10-14 · on GitHub
v0.14.0: pictures shrink before upload
Nothing to do when upgrading. A new optional setting,
NOTEFEED_SHRINK_IMAGE_BYTES, sets the size the web pages shrink a picture to before uploading it: 1 MiB by default,0sends pictures as they are, never more thanNOTEFEED_MAX_IMAGE_BYTES.Web UI
- Pictures shrink before upload: the title image, the compose box and the note editor scale a picture down (to JPEG if need be) until it fits
NOTEFEED_SHRINK_IMAGE_BYTES, so a photo straight from a phone's camera is taken. GIFs are sent as they are. - Title image: works from a phone; the row shows "Uploading…" and its own refusals, which were at the foot of the page, out of a phone's view. A hint says the feed's pictures can be picked there.
API and clients
- The API is unchanged; the client packages take the version of the release.
Pull requests
- #188 NOTEFEED #187: Shrink pictures before upload; title image works from a phone
- Pictures shrink before upload: the title image, the compose box and the note editor scale a picture down (to JPEG if need be) until it fits
notefeed 0.13.0
Released 2026-10-14 · on GitHub
v0.13.0: a redesigned web app
Nothing to do when upgrading: no settings, storage or API changes. Operators may want their privacy page to mention that the browser now remembers the feeds it opened (local storage, never sent to the server; see ADR 0030).
Web UI
- A new look with the same identity: notes as cards, icons where an icon is clear, light and dark.
- Feed page: on a wide screen, your feeds and the About & legal menu on the left, the composer and the timeline in the middle, and the feed's details, read link and tags on the right. On a phone, a chat-style bar at the bottom posts a note directly; + opens the full composer.
- Your feeds: the feeds a browser opened are listed in a switcher, the left column and on the start page, remembered in the browser only.
- Settings as grouped rows (Profile, Sharing, Privacy & access, License, Danger zone), still working without JavaScript.
- Single note: Edit, Copy link, Report and Delete in an action bar, docked on a phone, in the right column on a wide screen. One Preview toggle replaces the Write and Preview tabs.
- License, imprint, privacy and terms pages redesigned. The footer links are also behind an About & legal menu.
- Android: an installed notefeed is in the share sheet for text and links, and opens the chosen feed's composer with them.
API and clients
- The client packages are unchanged and take the version of the release.
Pull requests
- #184 NOTEFEED #42: the sandbox's cancel and refund deliveries as tests
- #186 NOTEFEED #185: redesign the web app
notefeed 0.12.1
Released 2026-10-14 · on GitHub
v0.12.1: managing a license subscription, cancel at the provider on refund
Nothing to do when upgrading. A self-hosted instance without a payment provider is unchanged.
Hosted service
- Manage subscription by key: on an instance that sells licenses,
/licenseopens the provider's customer portal for whoever has the key (cancel, payment method, invoices), throughPOST /api/licenses/portal. - A refund also cancels the subscription at the provider, which otherwise keeps a refunded subscription running.
/licenseshows the free and licensed tiers and the price, and the footer links it while licenses are sold; the feed settings confirm an entered key.
API and clients
- The client packages are unchanged and take the version of the release.
Pull requests
- #182 NOTEFEED #42: manage a subscription by key, cancel at Creem on refund, price on the license page
- Manage subscription by key: on an instance that sells licenses,
Oct 13
notefeed 0.12.0
Released 2026-10-13 · on GitHub
v0.12.0: /health also checks the image store, a terms page, and licenses per feed for the hosted service
Nothing to do when upgrading: without new settings an instance behaves as before, except for the two points under "Read before upgrading".
Read before upgrading
/healthcan now answer503because of the image store: withNOTEFEED_IMAGESset tofsors3, the check also asks that store (a folder read, or one listing of at most one object, capped at 3 seconds). An instance whose bucket or keys are wrong wasokbefore and isunavailablenow. With S3 billed per request, a probe every 30 seconds is about 2,900 listings a day.termsandlicenseare reserved feed names: posting to them answers400. A feed that already has one of these names is no longer reachable under it.
For operators
/healthsays which part failed: the body gainschecks(storage,images), eachokorunavailable. See Health check.- A terms page:
NOTEFEED_TERMS_FILEnames a Markdown file shown at/termsand linked in the footer, next to the imprint and the privacy page. See Imprint, privacy page and terms.
Hosted service
- Licenses per feed (ADR 0029): the server can now tell a licensed feed from a free one. This is for notefeed.me and is off unless a payment provider is configured; a self-hosted instance has no limits and nothing changes for it.
API and clients
- A new answer
402 license_requiredon posting a note, editing a note and changing the feed password, only on an instance that sells licenses. The OpenAPI description and the JS and Python clients are regenerated for it; the client packages are otherwise unchanged and take the version of the release.
Pull requests
- #181 NOTEFEED #42: licenses per feed on the hosted service
- #180 NOTEFEED #174: GET /health also checks the image store
Oct 12
notefeed 0.11.0
Released 2026-10-12 · on GitHub
v0.11.0: a distroless image (read before upgrading), a security fix in Next, a security policy and an SBOM per release
This is the server of 0.10.2 and 0.10.3 under the number it should have had: the image changes in ways an operator can notice, so it is a minor release. 0.10.2 and 0.10.3 stay published and are the same server.
Read before upgrading
- The image is distroless: Node and the server, no shell, npm or package manager (ADR 0028), so a scan of it reports what notefeed brings and nothing else. Two things stop working: a
healthcheck:of your own in the compose file that callswgetorcurl(remove itstest:line; the image's own check does the same), anddocker exec <container> sh. The data folder,PUID/PGIDanduser:behave as before.
Security
- Next.js 16.3.8 closes six advisories in 16.3.7, among them cache poisoning of statically rendered pages and a server-side request forgery in image optimisation (GHSA-cjq9-62q9-8jv4, GHSA-4jqv-mc3x-m676, GHSA-mcj8-r9mp-w47p and three with less reach). Upgrade.
- A security policy:
SECURITY.mdsays how to report a vulnerability privately and that only the newest release gets fixes.
For operators
- An SBOM per release: two CycloneDX files are attached below, one for the server's npm dependencies and one for what is in the image; the image carries an SBOM and a provenance attestation as well. See Security fixes and SBOM.
- A daily check of the dependencies and the published image for known vulnerabilities runs in the repository.
The client packages are unchanged; they take the version of the release.
- The image is distroless: Node and the server, no shell, npm or package manager (ADR 0028), so a scan of it reports what notefeed brings and nothing else. Two things stop working: a
Oct 11
notefeed 0.10.3
Released 2026-10-11 · on GitHub
v0.10.3: the release of 0.10.2 with its client packages
0.10.2 was tagged with a stale
uv.lock, so its client packages were never published. The server is the same; the notes of 0.10.2 apply and are repeated here.Security
- Next.js 16.3.8 closes six advisories in 16.3.7, among them cache poisoning of statically rendered pages and a server-side request forgery in image optimisation (GHSA-cjq9-62q9-8jv4, GHSA-4jqv-mc3x-m676, GHSA-mcj8-r9mp-w47p and three with less reach). Upgrade.
- A security policy:
SECURITY.mdsays how to report a vulnerability privately and that only the newest release gets fixes.
For operators
- The image is distroless: Node and the server, no shell, npm or package manager (ADR 0028), so a scan of it reports what notefeed brings and nothing else. Two things stop working: a
healthcheck:of your own in the compose file that callswgetorcurl(remove itstest:line; the image's own check does the same), anddocker exec <container> sh. The data folder,PUID/PGIDanduser:behave as before. - An SBOM per release: two CycloneDX files are attached below, one for the server's npm dependencies and one for what is in the image; the image carries an SBOM and a provenance attestation as well. See Security fixes and SBOM.
- A daily check of the dependencies and the published image for known vulnerabilities runs in the repository.
The client packages are unchanged; they take the version of the release.
notefeed 0.10.2
Released 2026-10-11 · on GitHub
v0.10.2: a security fix in Next, a distroless image, a security policy and an SBOM per release
Security
- Next.js 16.3.8 closes six advisories in 16.3.7, among them cache poisoning of statically rendered pages and a server-side request forgery in image optimisation (GHSA-cjq9-62q9-8jv4, GHSA-4jqv-mc3x-m676, GHSA-mcj8-r9mp-w47p and three with less reach). Upgrade.
- A security policy:
SECURITY.mdsays how to report a vulnerability privately and that only the newest release gets fixes.
For operators
- The image is distroless: Node and the server, no shell, npm or package manager (ADR 0028), so a scan of it reports what notefeed brings and nothing else. Two things stop working: a
healthcheck:of your own in the compose file that callswgetorcurl(remove itstest:line; the image's own check does the same), anddocker exec <container> sh. The data folder,PUID/PGIDanduser:behave as before. - An SBOM per release: two CycloneDX files are attached below, one for the server's npm dependencies and one for what is in the image; the image carries an SBOM and a provenance attestation as well. See Security fixes and SBOM.
- A daily check of the dependencies and the published image for known vulnerabilities runs in the repository.
The client packages are unchanged; they take the version of the release.
notefeed 0.10.1
Released 2026-10-11 · on GitHub
v0.10.1: a health check, and 410 for a removed feed
For operators
- A health check:
GET /healthanswers200 {"status":"ok"}when the instance and its storage answer,503 {"status":"unavailable"}when the storage does not. Always on, no password or token, logged atdebug.POST /healthanswers405now. - The image has a
HEALTHCHECKon it, sodocker psand monitors that read Docker's health status (such as Beszel) showhealthyorunhealthywithout any setup.
API
- The read API answers
410for a feed the operator removed.
Docs
- A page that compares notefeed to ntfy, Gotify, chat webhooks and note-taking apps.
- The hosted service's docs say how to report content and what happens then.
Client packages 0.10.1 (PyPI and npm
notefeed)- See the pull requests below.
- A health check:
Oct 10
notefeed 0.10.0
Released 2026-10-10 · on GitHub
v0.10.0: a report page, the operator's takedown, and private files
For operators
- A Report link on every note (
NOTEFEED_REPORT_URL, a URL template with{read_id},{note_id}and{file}), on the feed page, the note page and the read-only view. Unset: no link. notefeed stores no reports. - A report page of notefeed's own:
NOTEFEED_REPORT_ENDPOINTnames the endpoint of a form in an inbox you run (such as noticebox), and/reportshows the form and posts there, with the note's ids in hidden fields. With the endpoint set and no template, the Report link opens this page. - The operator's takedown:
POST /api/operator/takedownremoves a feed for good, leaves a tombstone and blocklists its images' hashes. NOTEFEED_IMAGE_UPLOADS=0refuses every image upload with403 images_off.POST /api/operator/images/movemoves image bytes into the configured store.- Files are served private, no-cache, never from a shared cache.
- One log line per request, without the feed name.
Web UI
- Write and Preview tabs on the compose box and the editor.
- The note box places the cursor behind a new picture's reference in the same step.
Client packages 0.10.0 (PyPI and npm
notefeed)- See the pull requests below.
Pull requests since v0.9.3
- #169 NOTEFEED #156: a report page of notefeed's own that posts to the operator's inbox
- #168 NOTEFEED #155: the operator's takedown, with a tombstone for the feed and a blocklist for its images
- #167 NOTEFEED #154: a Report link on every note, from the NOTEFEED_REPORT_URL template
- #166 NOTEFEED #152: NOTEFEED_IMAGE_UPLOADS=0 refuses every image upload with 403 images_off
- #162 NOTEFEED #146: Write and Preview tabs on the compose box and the editor
- #165 NOTEFEED #164: the note box places the cursor behind a new picture's reference in the same step, not a frame later
- #163 NOTEFEED #128: POST /api/operator/images/move moves image bytes into the configured store
- #161 NOTEFEED #153: files are served private, no-cache, never from a shared cache
- #151 NOTEFEED #150: one log line per request, without the feed name
- A Report link on every note (
Oct 8
notefeed 0.9.3
Released 2026-10-08 · on GitHub
v0.9.3: a notice on the start page, and a GitHub link in the footer
For operators
- A notice on the start page:
NOTEFEED_NOTICE_FILEnames a Markdown file of your own. Its text is shown as a red warning banner on the start page, above the introduction: the place to say that a service is still being built, or what you do not promise. It follows the rules of the imprint and the privacy page: read on every request, at most 256 KiB, raw HTML stays text, and the start-up log names the setting when its file cannot be read. Without a file, or with an empty one, the start page is unchanged.
Web UI
- Footer: a link to the project on GitHub, after Docs.
Client packages 0.9.3 (PyPI and npm
notefeed)- No changes; the version follows the server's.
- A notice on the start page:
notefeed 0.9.2
Released 2026-10-08 · on GitHub
v0.9.2: the imprint and the privacy page are your own files
The imprint and the privacy page come from the operator
- Two new settings,
NOTEFEED_IMPRINT_FILEandNOTEFEED_PRIVACY_FILE, each name a Markdown file. With a readable file,/imprintor/privacyshows it and the footer links to it. - Without a file there is no such page and no footer link. The image no longer contains the texts of the hosted service.
- The file is read on every request, so an edit shows at once.
imprintandprivacyare now reserved feed names.
If you run your own instance
Until now your instance showed the imprint and the privacy text of notefeed.me. After this update both pages are gone until you set the two settings. See "Imprint and privacy page" in the self-hosting docs.
- Two new settings,
Oct 6
notefeed 0.9.1
Released 2026-10-06 · on GitHub
v0.9.1: notefeed has moved to its own organisation
Nothing changes in how notefeed works. This release exists so that everything is published from the new home.
The project moved
- Repository:
github.com/notefeed/notefeed(wasMarceltov/notefeed). The old address redirects; issues and pull requests kept their numbers. - Container image:
ghcr.io/notefeed/notefeed, from this release on.ghcr.io/marceltov/notefeedstays at 0.9.0 and gets no more updates: change theimage:line in your compose file to keep upgrading. Nothing else in your setup changes. - Docs: still at https://docs.notefeed.me.
Client packages 0.9.1 (PyPI and npm
notefeed)- No code changes. The packages' repository and issue links point to the new address.
- Repository:
notefeed 0.9.0
Released 2026-10-06 · on GitHub
v0.9.0: a note and its pictures in one request, storage in a database, images in an object store
A note with its pictures is one request
- Multipart posts:
POST /api/v1/feeds/{feed}/notes(andPOST /{feed}) andPUTon a note also acceptmultipart/form-data: an optionaltextpart, up to 10fileparts andalt.<filename>fields. The server checks everything before the first write and removes what it stored if a later write fails. A raw single-file request is unchanged. - Every caller uses it: MCP
post_note, both clients (attachments), both CLIs (--attach) and the web compose box and editor. - Stricter text rules: names, titles, alt texts, tags and feed settings are one line with no control or text-direction override characters. A text sent with pictures is read in a worker with a time limit (
NOTEFEED_PARSE_TIMEOUT_MS). - Changed answers: a malformed multipart body is
400; a title or alt text with a forbidden character is400; the MCP request body limit is 16 MiB.
Storage backends (new)
NOTEFEED_STORAGEchooses where feeds and notes are kept:fs(default, unchanged),sqliteorpostgres. The database backends needNOTEFEED_SECRET; with PostgreSQL several containers can share the data. A new instance on a database starts empty: moving between backends is not built.NOTEFEED_IMAGESchooses where a database backend keeps image bytes:db(default),fs(a folder) ors3(any S3-compatible object store; there is no default endpoint). Going fromdbtofsors3needs no move.- Cleaning up the image store: with
NOTEFEED_OPERATOR_TOKENset,GET /api/operator/images/unreferencedreports the image files or objects that no note refers to, andDELETEremoves them. - Reading costs less on the file backend: a feed's folder is listed once per request, and a stray folder or link in it no longer breaks the listing.
Operations
- Metrics:
GET /metricsin the Prometheus format, off unlessNOTEFEED_METRICS=1, with an optionalNOTEFEED_METRICS_TOKEN. The docs include a Prometheus and Grafana setup. - Docs are restructured into sections with short pages.
- Web UI fix: adding an image no longer takes the focus back from the title or tags field.
Client packages 0.9.0 (PyPI and npm
notefeed)post()sends the text and itsattachmentsin one request; content may be empty for pictures only. The clients no longer check file names themselves: the server decides.- Upgrade: a 0.9.0 client needs a 0.9.0 server (an older server answers
415to multipart).post()withaltornametogether withattachmentsis aConfigError.
The container image is moving. This is the last release published as
ghcr.io/marceltov/notefeed. Later releases are published asghcr.io/notefeed/notefeed; change the image line in your compose file when you next upgrade.- Multipart posts:
Oct 3
notefeed 0.8.0
Released 2026-10-03 · on GitHub
v0.8.0: a note is a file, pictures are notes, and a note can bring its pictures
A note is a file (breaking)
- One API for every type.
POST /api/v1/feeds/{feed}/notes(andPOST /{feed}) takes the file's bytes as the body and its exactContent-Type(text/markdown,image/png,image/jpeg,image/giforimage/webp); the body is checked against the type. Metadata isX-Note-*headers.PUTreplaces a note's content andPATCHchanges its title and alt text. The JSON and form post bodies are gone, so a script that relied on curl's default type needs-H "Content-Type: text/markdown". - Pictures are notes of their own, listed in the feed, shown on the note page and sent to RSS readers as enclosures. A note's JSON has
type,file,file_url,size,titleand, for text types,content;kindandmarkdownare gone. Every note can have a title. - Storage: content is kept as posted with its metadata in a sidecar file, and note ids carry a UUID v7 so notes of the same second keep their order.
- Feeds: a feed's read id can be chosen when it is created and changed later; files are served under it, and relative
links follow it, also in RSS. - Web UI: the compose box and the editor post and edit every note through this API (it needs JavaScript), and a tags field sits next to the Add image button.
Pictures with a note (new)
- Attachments:
attachmentsonpost()in both clients,notefeed post --attach PATHin both CLIs andattachmentson the MCPpost_notetool post the pictures first, one note each, then the text, withswapped for each file name (a picture the text never refers to is added at the end). Everything checkable is checked before the first request. If an upload fails, the error names the picture and lists those already posted; the text is not posted and nothing is rolled back. - MCP:
post_fileposts any accepted file and replacesupload_image.
Client packages 0.8.0 (PyPI and npm
notefeed)post(content, type=…),edit(id, content)andupdate(id, title, alt)work for every kind of note;notefeed post --filereplacesnotefeed image.post()returnsattachments(empty without any).- Upgrade: these clients speak the file API, so a 0.8.0 client needs a 0.8.0 server. Compare the exact result of
post()in tests: it now hasattachments.
- One API for every type.
Oct 2
notefeed 0.7.0
Released 2026-10-02 · on GitHub
Tags on notes, per-feed passwords, editing and deleting, images, feed settings, and optional sign-in.
Tags
- Label a note when you post it: a
tagsarray in a JSON body, a repeatedtagsform field, theX-Note-Tagsheader for a raw body, or the MCPpost_notetagsargument. At most 10 per note, each 1 to 32 characters of lowercase letters, digits,-,_,.and:(soenv:prodworks); capitals are folded and duplicates dropped. - Filter with
?tag=cion the note list, the read API, MCPlist_notes, the feed and read-only pages, and the RSS feed (/r/<read id>/feed.xml?tag=ci), so a reader can subscribe to one kind of note. - Shown next to the title as links, in the API's note JSON (
tags) and as<category>in RSS. Tags are free labels, not verified, and public with the note. An edit keeps them; they can't be changed after posting.
Notes and feeds
- Per-feed passwords: a feed can have its own password, set by its first post.
- Edit and delete notes, over the API, the web UI and MCP.
- Feed settings and deletion: a title, description and title image, and deleting a whole feed. New feeds get a stored random read id.
- Images in notes, uploaded to a feed and served under its read id.
- Reserved feeds with a stable read id.
- Web UI: a settings page, header icons, a footer with docs, imprint and data privacy pages, a web manifest, favicon and share image.
Sign-in
- Optional OIDC sign-in with a verified sender on notes, with several providers at once. Private by default: without it nothing about a person is stored.
- Logging through pino across the backend.
Client packages 0.7.0 (PyPI and npm
notefeed)posttakestags,notesandread_notes/readNotestaketag, andnotefeed post --tag/notefeed notes --tagdo the same.Notehas atagslist.- Also new since 0.6.0: edit, delete, image upload, feed settings and per-feed passwords in the clients and the command.
- Upgrade:
Note.tagsis always present in the API, so a 0.7.0 client expects a 0.7.0 server.
- Label a note when you post it: a
Oct 1
notefeed 0.6.0
Released 2026-10-01 · on GitHub
An MCP endpoint, with OAuth login for locked instances.
MCP
- AI assistants can post and read notes at
/mcp. Three tools:post_note,list_notesandget_note. The feed name is a parameter of each tool, so one endpoint serves every feed. Posting follows the same rules as the HTTP API: size limit, rate limit, caps, and the first post creates the feed. - Claude Code:
claude mcp add notefeed --transport http https://notes.example.com/mcp. On an instance with a password, add--header "Authorization: Bearer <password>". - Claude.ai and Claude Desktop: add a custom connector with the
/mcpURL. - The endpoint speaks MCP 2026-07-28 and nothing older. An older client gets a
400naming the supported version.
OAuth 2.1 login
- For clients that can't send a header. On an instance with a password, a connector opens notefeed's own login page, which names the client and the host it returns to. Enter the instance password and press Allow. On an open instance these endpoints answer
404. - Nothing is stored. Client ids, codes and tokens are signed with a key derived from the server secret and the password. Changing
NOTEFEED_PASSWORDsigns every client out. - Lifetimes: a code lasts 5 minutes and works once, an access token 1 hour, a refresh token 30 days and is replaced each time it's used.
- OAuth needs the instance's public
https://address: setPUBLIC_URL, orNOTEFEED_TRUST_PROXY=1behind a reverse proxy.
Changed: forwarded headers need
NOTEFEED_TRUST_PROXY- Without
PUBLIC_URL, notefeed used to build links fromX-Forwarded-ProtoandX-Forwarded-Hoston any connection, so a client could pick the host in RSS links, API responses and redirects. It now uses them only withNOTEFEED_TRUST_PROXY=1, and otherwise theHostheader overhttp. - Behind a reverse proxy without
PUBLIC_URL: setNOTEFEED_TRUST_PROXY=1orPUBLIC_URL, or links will come out ashttp://.
Client packages 0.6.0 (PyPI and npm
notefeed)- No changes since 0.5.0. The version follows the release.
Under the hood
oauthis a reserved feed name.- ADR 0007 records the MCP endpoint and OAuth decisions.
- AI assistants can post and read notes at
notefeed 0.5.0
Released 2026-10-01 · on GitHub
Feeds, read links and a REST API.
Breaking: this release replaces the single token-protected feed of 0.3. NOTEFEED_TOKEN, /api/notes and /feed.xml are gone, and the client packages change accordingly (see "Upgrading" in the client docs).
Feeds
- One instance, many feeds. A feed is identified by its name: post to
POST /<feed>, read it at/<feed>. There are no accounts. The name is the write key, so pick one that's hard to guess (the start page suggests one). - Read links. Every feed has a read-only link,
/r/<read id>, plus RSS at/r/<read id>/feed.xml. They show the notes but never the feed's name, so they're safe to share or put in a feed reader. - Optional instance password (
NOTEFEED_PASSWORD): it locks posting and the web UI, while read links stay public. Wrong passwords are rate-limited, and after logging in you return to the page you came from. - Limits for public instances:
- posts are rate-limited per client (
NOTEFEED_RATE_LIMIT,NOTEFEED_TRUST_PROXYbehind a proxy) NOTEFEED_MAX_FEEDSandNOTEFEED_MAX_NOTES_PER_FEEDare optional caps- bodies are capped while they stream in
- posts are rate-limited per client (
REST API
- Versioned and documented under
/api/v1: post notes, list a feed's notes as JSON with paging (limit,before→next), get one note, and read by read id without a password. Errors are JSON with a stablecode. - Self-describing: each instance serves its OpenAPI description at
/api/v1/openapi.json, and docs.notefeed.me renders it. It's generated from the server's code. curl -F markdown=@note.mdworks, and so doescurl -d. HEAD works on every GET endpoint.
Client packages 0.5.0 (PyPI and npm
notefeed)- Generated from the API description, with a small
Clienton top:post,notes()(walks every page),note, the read-id variants, andfrom_env()/fromEnv(). Errors are classes mapped from the API's code, and a redirect or a non-API answer is an error, never a silent success. - New command:
notefeed notes [--limit N] [--json]. - Python now needs 3.11 or newer and depends on httpx. Node still has no dependencies.
Web UI
- A start page to open a feed, a page per feed, and read-only views.
- The compose box works without JavaScript and shows errors inline with it.
Under the hood
- The server code is a framework-free backend behind a single boundary module.
- Every POST is handled by one write path, routed by method and path.
- Architecture decisions are recorded in docs/adr (0001–0006).
- End-to-end tests run in a real browser against the production build.
- One instance, many feeds. A feed is identified by its name: post to
Sep 30
notefeed 0.3.0
Released 2026-09-30 · on GitHub
New license, new home.
-
The notefeed server (web app and Docker image) is now licensed under AGPL-3.0. Self-hosting stays free. Anyone running a modified version as a service must publish their changes.
-
The client packages (PyPI and npm
notefeed) are licensed under Apache-2.0. -
Versions up to 0.2.x remain under the MIT License.
-
The documentation moved to https://notefeed.me.
-
The package metadata now has homepage, issues and changelog links, and keywords.
-
The Docker image no longer bundles the unused
sharpimage library, so it is about 70 MB smaller (264 MB).
-
notefeed 0.2.0
Released 2026-09-30 · on GitHub
First tagged release of notefeed.
-
Post markdown notes over HTTP (
POST /api/notes, bearer token) or in the web UI; read them back as RSS at/feed.xml. -
Every note is a plain
.mdfile. With the./databind mount the files belong to you, so you can grep them or keep them in git. -
Client packages for Python (
pip install notefeed) and Node (npm install notefeed), each with anotefeed postcommand. -
Documentation: https://marceltov.github.io/notefeed/
-
The URL and token are set once, when you create the
Client. The libraries no longer readNOTEFEED_URL/NOTEFEED_TOKEN; only thenotefeedcommand does. -
The top-level
post()helper was removed. UseClient(...).post(markdown).
-