# Changelog

How updates work, and how to turn automatic updates off, is on the [home page](https://adorably.io/#updates).

Every release of the Adorably mod, newest first. Versions are tags `adorably-X.Y.Z`; every published version stays downloadable at `https://adorably.io/dl/adorably-X.Y.Z.zip`, pinned by its SHA-256 in the marketplace file.

**Update policy.** From 0.1.1 the mod updates itself by default: at most once a day, in an interactive session, it runs Claude Code's own plugin commands, and the new version applies in your next session. Turn that off with `/perks settings updates manual`; then `/perks` shows a line when a release is out and you update with `claude plugin update adorably@adorably`. Every version stays downloadable, pinned by its SHA-256. Entries that change what the mod reads or sends are marked **\[reporting\]**; when one changes what is sent, the mod asks for consent again before sending anything, so an update never starts sending something new without a yes. Entries that increase interruptions (a higher card cap, a new kind of card, a new moment that can trigger one) are marked **\[attention\]**; the mod asks again before applying them, and until you say yes it keeps the limits you had.

## 0.1.1 (2026-10-26)

### Updates

-   The mod now updates itself by default. At most once a day, in an interactive session after you turned it on, when the api's config names a newer release (`latest_mod_version`), it runs Claude Code's own plugin commands in the background: `claude plugin marketplace update <marketplace>`, then `claude plugin update adorably@<marketplace>`. When that works it says "Adorably updated to X.Y.Z — it applies in your next session". It never runs in a headless session, with `CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC` set, after `/perks off`, while the kill switch is on, or in a copy loaded with `--plugin-dir`, and it never edits your `settings.json`.
-   `/perks settings updates auto|manual`, with a button in the pane's Settings tab. With updates manual, or when an update fails (the reason goes to the debug log), `/perks` shows one line naming this install's real plugin id: `Adorably X.Y.Z is available: claude plugin update adorably@<marketplace>`.
-   Updating sends nothing new to the api. Claude Code fetches the marketplace file and the release zip from adorably.io, the same requests a manual update makes, with no install id. Every version stays downloadable and pinned by its SHA-256, and an update that changes what is sent asks for consent again. The consent question now says the mod keeps itself up to date and how to stop it.
-   0.1.0 does not update itself. Update it once by hand (`claude plugin update adorably@adorably`); from 0.1.1 on it keeps itself current.

### What the mod sends

-   **\[reporting\]** Each events batch now carries the Claude Code version (`host_version`), so a break in Claude Code's mods API shows up per Claude Code version.
-   **\[reporting\]** Each events batch now carries a random `batch_id`. It stays the same when the batch is retried, so the server stores a batch once.
-   Every request now carries the mod's version in an `x-adorably-mod` header, including the config and catalog downloads, which carry no install id. The mod version was already sent with events; the server now also counts config requests per mod version and country.
-   Every request now carries the User-Agent `adorably/<version>` instead of the runtime's own (for example `Bun/1.4.4`), so the headers say nothing the privacy table does not. No user agent is stored with a claim.
-   The sent / never-sent rows are now one list in the mod (`hooks/privacy.ts`), used word for word by the consent question, `/perks privacy`, the pane's Privacy tab and its footer. The tables on adorably.io are checked against it, and the footnote under them names both headers.
-   **\[reporting\]** Consent version 2. A yes given to 0.1.0 counts for nothing in 0.1.1: the mod sends nothing and asks again at the start of your next interactive session, with one sentence on what changed.
-   New installs make a random secret on your machine and use the first 32 hex digits of its SHA-256 as the install id. The secret is never sent. Installs made before 0.1.1 keep their id.
-   A batch the server refuses as malformed or too big (400/413) is dropped instead of retried forever. Batches that fail with 429, a 5xx or a network error are retried with the same `batch_id`.

### Deleting your data

-   `/perks forget` now makes the server anonymize your claim records instead of deleting them: the install id, the hashed IP and the country are removed, and the offer, time, surface and where you claimed it are kept as the record of what was claimed. The install record and stored batch ids are still deleted.
-   `/perks forget` says truthfully what happened: whether the server deleted your data, could not be reached, or was not contacted because `CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC` is set. Running it twice says there is nothing left. Your install id is shown in the Adorably pane under Privacy (until the session ends, after a forget), never in command output, which the model reads.
-   After `/perks forget` in one session, every other running session notices that consent and the install id are gone the next time it would queue an event, send, claim or scan, and goes quiet. It never makes a new install id (only **Turn on** makes one), an event it was about to queue is dropped, and it sends nothing. A forget caught halfway (consent still stored, install id gone) stops the other sessions too.
-   `/perks forget` on an install that never sent anything makes no request and says the server holds nothing.

### What the mod reads

-   **\[reporting\]** In `prisma/schema.prisma`, the mod now reads the `provider` of the `datasource` block (`postgresql`, `mysql`, `sqlite`, `mongodb`) and adds `has:postgres`, `has:mysql`, `has:sqlite` or `has:mongodb` when the catalog's dictionary knows the tag. Models and the rest of the schema are not read. This is local only and nothing new is sent, so the consent version stays 2; the consent question names it, and so do adorably.io's home page, privacy policy and llms.txt (a site test fails if the site's list of what the mod reads falls behind the consent question).

### Attention gate

-   Every limit on when Ado may interrupt (cards per session and per week, the quiet first sessions and minutes, how long a card stays, the relevance a card needs, how often the pane opens by itself, how long a mute holds) is now in one place, `hooks/attention.ts`, and **Turn on** stores the limits you agreed to. When a new version's limits are looser on any of them, the mod keeps the stricter of the two and asks at the start of your next interactive session, in one sentence naming what would change ("Allow" or "Keep my limits"). Headless sessions never ask. Caps can only go up with your explicit yes: `/perks settings cards-per-week` only lowers the cap, and no update or remote config raises a limit for you. Such changes are marked **\[attention\]** in this changelog. 0.1.1's limits are the starting point, so nothing in 0.1.1 is marked; a 0.1.0 install answers the new consent question (consent version 2) before anything in 0.1.1 runs.

### How Ado decides

-   Relevance alone decides whether a card shows: an offer must newly match a real gap (a `needs:` tag) or match on two or more signals, right after something you did. Public perks now get cards on the same terms as sponsored offers.
-   Offers are ranked by relevance × quality × freshness. A bid only breaks ties, so a paid offer never outranks a better-matched one.
-   Every card starts with its label (**Sponsored** or **Public perk**). A sponsored card also names the best-matching public perk in its category ("Also free: ...").
-   The ranking rules are shown in plain words under `/perks why`.

### Settings

-   `/perks settings cards all|public|off`: which perks may get a moment card.
-   `/perks settings cards-per-week 0..3`: lower the weekly cap; 0 means no cards. It never raises the cap above three.
-   `/perks settings ado on|off`: with Ado off, cards are plain sentences with no sprite and no "Psst!".
-   The pane's Settings tab has buttons for each. A value Adorably does not recognize prints the usage line and changes nothing.

### Screen

-   The perks count is now a dim `◆ N perks` label among the session modes in the prompt footer. The mod no longer uses the status line.
-   The pane shows at most two perks per category, then a "N more" row that expands the rest.
-   After a claim the row stays where it was and its button becomes **Open ↗** or **Copy code**; it reads **Claiming…** while the claim is in flight, and presses on other perks within 1.5 seconds of a claim are ignored. Claimed perks from earlier sessions have a keyboard button and show their link dim.
-   When the pane takes the keys, the first button has the focus; switching tabs keeps the focus on the chosen tab. Narrow panes truncate labels instead of wrapping them.
-   With the network off and no saved catalog, the pane says so instead of "no perks match".

### Fixes

-   `/clear` resets only the conversation. Adorably keeps its state, its footer glyph, the 10-minute window and its timers; only a real exit stops them.
-   Escape closes a pane you opened (`/perks`, `/perks why`, `/perks privacy`, `/perks settings`). A pane that peeked open by itself is left to close at the end of the turn.
-   Catalog text with a control character (an offer's name, value, line, category or code, a config message, a signal phrase, a tag) is dropped before it is drawn, so one bad entry can no longer blank the whole pane.
-   First run: only "Turn on" and "Not now" count. A dismissed dialog or free text records nothing, says so, and asks again next session. Headless sessions (`claude -p`, the SDK) never ask and never record an answer. When two sessions start at once, the first answer wins.
-   A manifest changed by something other than an install command (`npm pkg set`, `git checkout`, an editor) is noticed at the end of the turn and when you open `/perks`.
-   A tag removed under `/perks why` stays removed for that project only (0.1.0 removed it everywhere; an old list moves to the first project that reads it).
-   A claim that cannot reach the server opens the vendor's page directly and says the claim was not recorded. A claim answer that redirects anywhere but Adorably's own claim link is refused.
-   A catalog that cannot be saved locally still matches from memory.
-   With the API unreachable, a saved config over 14 days old turns the mod quiet until a fetch succeeds, and a catalog not confirmed for 14 days shows public perks only.
-   An offer whose targeting uses a rule this version does not know is hidden (fail closed); tags from tag families added later are kept.
-   An Edit or Write that starts while the pane has peeked open closes the peek first, so Claude Code's Diff pane still opens for that change. The edit can wait up to 0.25 seconds for this, at most once a session.
-   The pane no longer peeks open once the week's cards are used up, including after you lower cards-per-week.
-   Perks visible in a pane that peeked open by itself are recorded as shown.
-   A mute, dismissal or claim in one session reaches every other running session within about 5 seconds.
-   With a demo or staging api, a claim never falls back to a vendor's own link; a claimed perk with no link says "No link" instead of showing a button that does nothing.

### Demos and staging

-   `ADORABLY_API_BASE` points the mod at another api, for demos and staging only: an `https://` URL, or `http://127.0.0.1[:port]` / `http://localhost[:port]`. Anything else is ignored, with a line in the debug log. Every request, and the check that a claim link is the api's own `/r/` redirect, then use that base.
-   The repo has a local demo api (`scripts/demo-api.mjs`) serving fictional sponsored offers from `seed/demo-perks.yaml`. Its claim links open a local page that says the offer is from a fictional company, never a vendor's site; a malformed offer id on that page is a 404, like an unknown one. Demo offers never reach the production catalog. The demo api runs on Node 20; building its catalog needs the repo's Node 26.

### Wording

-   adorably.io's home page leads with "The right perk, right when you add the package." Everywhere the site, llms.txt and the marketplace description promised that your code stays on your laptop, they now say "Nothing about your code is sent.": Claude Code itself sends your code to Anthropic, so the old line claimed more than Adorably controls.
-   The home page's sections now name what they show: "We ship the catalog to your code, not your code to our servers.", "Built to stay out of your way" (the frequency rules, settings and update default as the mod applies them), "Clear disclosures. Zero prompt pollution." (Ado never writes to your prompt or transcript, and `/perks` replies, which the model reads, name no offers or tags) and "Don't trust our privacy policy. Read the TypeScript." (the Claude Code mod is open source; the server is not). The second link under the headline is "See the exact network payload".
-   The marketplace description is "Ado, a pocket fairy in Claude Code, shows dev-tool perks when they fit. Matching runs on your machine; nothing about your code is sent."

### Catalog and server

-   Hosting perks now target the kind of app: full-stack JS frameworks, web frontends and backend servers each have their own gap. Cloud credit programs are narrower (for example AWS Activate only for launched repos with containers or object storage).
-   The api serves the catalog byte for byte; mods hide disabled and expired offers using the config, and the server still refuses them on claims and redirects.
-   Each release sets `latest_mod_version` in the api's config to the version it ships, and changes nothing else there. It reads the config again right before writing and stops, writing nothing, if an operator changed it in between. It uploads only the production catalog, and fails if that catalog holds a demo offer.
-   Each release checks the exact zip it uploads: only the mod's own files (`.claude-plugin/plugin.json`, `hooks/`, `types/`, `README.md`, `LICENSE`) and no backend names (`scripts/check-mod-zip.mjs`).

## 0.1.0 (2026-10-25)

First release, for the week-one test (M0).

-   Local matching of dev-tool perks from dependency manifests, config file names and `.env.example` variable names. Never reads `.env`.
-   Status line (`◆ N perks`), `/perks` pane with matched public perks, claims through tracked links.
-   Commands: `/perks`, `/perks off|on|why|privacy|settings|forget`.
-   **\[reporting\]** Sends, after consent only: a random install id; ids of offers shown, dismissed, muted, opened, claimed, and sponsored offers that matched but were not shown; a per-session match count; surface; mod version. Country is derived by the server. `/perks forget` deletes local data and asks the server to delete its rows for the install id.
