The rules the product follows, the versions that broke them, and what is deliberately not built. Condensed from the changelog, which has the measurements. Nothing here is a roadmap.
The rule that produced most of the others: zero is a valid outcome. There is no floor, no fallback move, no minimum count and no ceiling. Every failure class this project has recorded came from something that guaranteed a non-empty row.
Rules, and the failure behind each
Never fake output
Earlier builds fell back to canned suggestions when the API failed, which made a broken integration look like a working one. Degraded states now say what actually happened: a limit reached, a parse failure, a network error.
Clicking is the only input
There is no box to type into anywhere in the product. Material you have to supply becomes a <paste here> slot inside the written prompt, which you fill in the message box before sending.
One move, one verb
Within a single move, if a bullet could be sent on its own as a complete request, it is a second job and does not belong there. Between moves the rule inverts, deliberately: every move must stand alone as a complete request. That is the difference between a menu and a checklist, and it is the whole point of the row.
No categories or personas
An earlier version tagged suggestions by lens (sharpen, explore, constrain). It made the output feel like a taxonomy exercise instead of a colleague talking. Removed.
One control, one job
The trigger and a type-it-yourself chip once shared a row and did different things, which needed a rule to keep them apart. The second control is gone; the rule it needed is why a second one should not return without a reason better than convenience.
Selectors degrade quietly
If claude.ai's page structure changes, the extension goes silent rather than breaking the page. The selectors are pinned constants at the top of the content script.
By version, newest first
0.9.99- The trigger above the message box is now the app icon's C with a face inside it, so the toolbar icon and the button are one mark. And a reply in which the model repeated its answer no longer costs a hosted user the row: both paths now read the model's output with one shared parser.
0.9.98- Start fresh is now Same session, new chat, because it carries the thread on rather than starting over. The cost line reads "≈ n tokens off every message", the trigger's bubble says Next move ✦, and the store description and screenshots lead with long sessions.
0.9.97- When the conversation could only be read from the page, which keeps just the rows near where you are, the diagnostic card and the console now say so instead of quietly working from the tail.
0.9.96- A new app icon: a frosted-glass C on a teal-to-violet field, replacing the rounded mascot. The extension icons, the store and website marks, the favicon, the social preview and the promo tiles all move to it. The worker's build number follows the manifest so the guard stays satisfied; nothing the extension or worker does changes.
0.9.95- The name says the promise: CONTEXA for Claude - Save tokens, and the short description leads with the saving and names Start fresh. Both are store fields, so the wording is a package version rather than a listing edit. Every token earned stays as the rule the copy has to pass, not as the copy. This site's tagline, title and preview title follow.
0.9.94- The session's project id turned out to be its uuid in another spelling (base58), so Start fresh on a Cowork session opens the right project with no lookup at all, and the chip names it. Five rounds of searching the API for a mapping are removed.
0.9.93- The session record itself is searched first for its project's uuid, and the diagnostic card shows every key it carries instead of the first twelve.
0.9.92- The session's project is also looked for on the session's own conversation record, in the org's conversation list and in each project's, and on the code API's session list.
0.9.91- The project list does not carry the session record's project id, so the lookup now also reads each project's detail, the code API's project list, and what the session page itself fetched to show its project's name. The last is used only when exactly one project was fetched.
0.9.90- The session page's first project link turned out to be the sidebar's first project, not the session's own. The project's address is now asked of claude.ai's project list by the id in the session record; when nothing answers, the chip copies the brief and opens no page it cannot name.
0.9.89- The project page's address comes from the session page's own link to it, not from an id in the session record, which turned out to be a different kind of id.
0.9.88- On a Cowork session, Start fresh now opens the session's project page and the brief lands in its composer by itself, which is what the field saw happen. The probe that found Cowork's endpoints is retired; the diagnostic card stays.
0.9.87- The first brief off a live Cowork session: 444 tokens instead of 124k per send, measured. And the landing stopped needing the new session's address: a parked brief lands on any claude.ai page that is not an existing conversation, has a message box and holds no messages yet.
0.9.86- The first live fork on a 123k-token Cowork session failed with a message that covered three causes. A brief cut at the output ceiling, or broken as JSON by raw line breaks, still carries its text, so both paths now salvage it, cut it at a clean line and flag it partial, as a cut row of moves has always been. The ceiling rises to 2,000 tokens, and the diagnostic card names the cause of a failed call.
0.9.85- On a Cowork session the moves and the brief now read the user's turns from both ends of the event stream, the first page for the goal and the last three thousand events for the present, instead of the earliest twenty-six of twenty-three thousand. Start fresh on Cowork copies the brief and opens the new-session screen, where the extension lands it if it finds a composer. The three-tap diagnostic opens from any card.
0.9.83- The line rendered on a live Cowork session: about 124k tokens re-read per send, exact, from the session's own record, where the page held six thousand characters. What is left is the brief, and this build asks the event stream how it can be read from the end rather than walked from the start.
0.9.82- Both session reads answer now. The extension sends the same headers the page sends, reads the token count wherever the record keeps it, recognises a user turn by the event's type or its payload's role, and walks the event pages on a click rather than at render.
0.9.81- The session record answered the extension with a 400 and the page with data, so the probe now records the request shape of the page's own session calls, header names and API-version values only, and the extension sends the API version header itself.
0.9.80- The number the plan was for. A Cowork session is a Claude Code session in Anthropic's cloud, and the page fetches its record, which carries the context the next message will re-read, exact. The session it was found on: 123,813 tokens, where the page's rendered part measured 6,324. The cost line on a Cowork page now shows that number, the moves and the brief are mined from the session's real turns, and the fork copies the brief for a new session rather than opening a chat that would not have the session's folders and tools.
0.9.79- Two cards from the field. On a chat, the page's API answered and the session the moves are mined from is now the whole one, six messages where the page showed three. On Cowork, the page's own calls showed the session's base and not its content, so the probe now also records WebSocket and EventSource connections and other hosts, and four read-only requests under the session's base report their status and key names, never values, into the card.
0.9.78- The card said where it was: a Cowork session, not a chat. Cowork keeps three to five blocks on the page and talks to an API this product does not know and will not guess. A small script in the page's own world now records the paths of the API calls the page itself makes, paths only, never a body or a header, and the diagnostic card lists them. A field diagnostic, to be removed once the endpoint is known.
0.9.77- The first diagnostic card from the field: a long chat on a phone held three blocks and one user turn in its DOM. So the moves and the brief were being mined from a single message, on the page where the whole session mattered most. When the page's API answers, the user's own messages now come from it, whole and in order, under the same clamps as before; the DOM read stays the fallback. The card also stopped saying "not asked" while the API was still answering: it tells pending, no conversation id, failed and ok apart, and updates itself when the answer lands.
0.9.76- The second field session said the cost line still never came, on threads whose every reply was huge, so the rendered read is blind on that page in a way no DOM arithmetic fixes. The extension now asks the page's own API for the conversation, same origin, read-only, with the page's own cookies, and counts it; the number is computed on the page and the JSON is dropped. A moved endpoint or a refusal is one console line and the rendered estimate stands, the same rule the selectors live under. And because a phone has no console and no tooltip, three taps on the CONTEXA wordmark now draw a diagnostic card: the version, what was measured and from where, what the API said or why it did not, the turns, the model.
0.9.75- The first field session of 0.9.74, on a phone, found two things in an hour. The model line rendered on real claude.ai, which verified the one selector nobody had checked. And a plainly long chat never drew the cost line: the page holds only the rendered part of a long thread, so the estimate read a fraction of it. The read now scales by how much taller the page is than the part on screen, capped, and the wordmark's tooltip (a long press on a phone) says what was measured. Also: a chat that loaded already finished, with no streaming flag on its last reply, could sit forever with no card, because the fallback timer was armed only by a change the page never made. It is armed once at attach as well.
0.9.74- Two nudges, one line, no button. Three short messages in a row on a thread heavy enough for it to matter, and the card says that each of them re-read the whole thread and that one message asking for the whole thing reads it once. A short question sent on Opus, and the card says Opus spends about 2.5× Sonnet's usage per token (the API list price; claude.ai's own weighting is not published) and that a question this short is what Sonnet is for. The page's model is read from claude.ai's own selector; no selector, no line. The long-thread cost line outranks both, because it has an action. The extension cannot switch the model or merge messages for you; it can only say, at the one moment the pattern is complete and the composer is empty.
0.9.73- The exit from a long thread. Every message sent on claude.ai re-reads the whole thread, so on a long one the cost of the next send is the size of everything on the page. Above about 12,000 estimated tokens the card now says that number next to the mascot, with one control beside it: Start fresh. It spends one call on a brief of the thread, written by the same rules as a move (nothing the session did not say, the user's own words for facts, a paste slot for anything the new chat will not have), shows the brief as the hover text of one chip, and that chip opens a new chat with the brief already in its message box. Nothing is sent; the user reads it and presses send. A thread with nothing to carry over gets an empty brief and says so. The console logs tokens before against tokens after on every fork, which is the measurement the thesis's open question was waiting on. The worker grew a second endpoint for it, sharing every gate and the same daily twenty. The second control since the pencil chip went, and it earns its place by being the way out of a thread rather than a second way into it.
0.9.72- The first gap the thesis named is closed. The worker had sent the system prompt as a cacheable block since 2026-08-27; the extension, on your own key, sent the same prompt as a plain string, so a press paid full input price for the ~2,400-token prefix while the row looked identical. Both paths now send the same block from the same code, with the same fallback to an uncached request if the API ever refuses it, and the build fails if the two copies drift. Nothing a user sees changes; what an own-key press costs does. Both paths also log what the API reports about the cache on every call, and the diagnostics carry the same two numbers, so a cache that has silently stopped working is visible in a console instead of only on an invoice.
0.9.71- The motto. Every rule in this list refuses to spend a token that was not earned: the empty card, the lazy call, the pinned first turn, the one-verb prompt. Written down as Every token earned, with the argument in
docs/token-savings-thesis.md, and carried into the extension's name, the store listing, the promo tiles and this site's tagline, which had said "Claude prompts, without the writing" since the site existed. No change to what the extension or the worker does; the worker's build number moves with the manifest because the build guard requires it. 0.9.70- On phones, a browser's force-dark mode was inverting the mascot's face. It inverts flat fills darker than one brightness threshold, and gradient fills (SVG paint servers) only when brighter than a higher one, which dark ink never reaches. A scan of all 16,777,216 sRGB colours found no flat colour that holds 4.5:1 against the white of the eye in all four render modes (no force-dark, and the cielab, hsl and rgb inversions); the best possible was 3.13:1. So the escape was the role, not the colour: the pupils, mouth and whisper now paint through single-colour gradients, and every pixel of ink is byte-identical across all four modes. The test suite asserts the rule in both directions.
0.9.69- A field screenshot from a phone showed washed-out pupils, so 0.9.69 darkened the ink. The next screenshot from the same phone had no pupils at all and a white mouth: darker in, lighter out. A fix pointed the wrong way, and the direction of the failure was the diagnosis. 0.9.70 has it.
0.9.67- The action gate's drops were read for the first time, from a live tail of the worker across ten sessions, half of them in Serbian. 36 moves came back and 14 were dropped; nine of the drops were doable clicks the verb list did not know. The gate fails closed, so an unknown verb does not degrade a row, it empties one. Verbs were added; 0.9.68 added one more, found by verifying that release.
0.9.66- A third gate, which required a spread of sources across the row, was removed after measurement: one run in six was emptied by it, and every row it took was good.
0.9.64- An empty row started saying which kind of empty it is. Three causes had drawn one identical card: the model earning nothing (the product working), the action gate finding no verb it knew, and the spread gate dropping an all-reply row. Only the first is honest. The diagnostics were console-only, and the product is field-tested on a phone, which has no console, so the card now carries the reason. The same release moved the result cache out of the service worker, which Chrome tears down at will; a second press under the same reply had been a fresh sample.
0.9.59- The field test reached a phone: 0.9.58 sideloaded on Android with an own key, and mobile worked with nothing changed. The defect it found: on a short session with a long enumerative reply, the row transcribed the reply's own list of options, and the evidence gate scored that as flawless. The gate built to prevent invention was quietly selecting for transcription. The prompt now names copying the reply's list as the most seductive failure.
0.9.58- The history-mining pivot. It stopped reading the reply for a question and started reading your own messages across the whole session for an idea: up to four independent moves, each send-ready. The click-to-answer interview, its pagination, the free-text box, the fifth chip, and the three-generation schema negotiation were deleted, 4,222 lines in all. The first message was pinned and the oldest middle ones made to drop first, whole messages only. Grounding widened to your messages plus the reply; checked against the reply alone, a working product would have reported itself broken.
0.9.55- The mascot became the trigger: a real button with the label "What now?", a hover bubble that can never intercept a click, a fade instead of a pop-in under reduced motion.
0.9.53- The model call stopped happening for every reply and started happening on the press. Before, every completed reply spent a call, so a twenty-message conversation could exhaust the day without a single click. The larger consequence was a side effect: nothing about the conversation leaves the page until a deliberate click. Capture of the reply stayed eager, because it is free and the page is settled at that moment; only the call moved.
0.9.31- The Chrome Web Store approves updates on its own clock, so no deploy order avoids a window in which old and new clients hit the same backend. The worker learned to serve two client generations at once. A bug caught by its own test: a parser that read one key only would have turned every legacy call into "the model earned nothing", a total outage wearing the mask of correct behaviour.
0.9.30- The product became a click-to-answer interview: one question at a time, numbered options, a free-text "Something else". All of it was deleted at 0.9.58.
Not built
- A prompt library, or templates with variables.
- Cross-device sync. It would need accounts, and the device token is anonymous by design.
Status
Version 0.9.99 is the number in the extension's manifest and in the worker's BUILD constant; the worker's /v1/health reports it with the model and the limit, so a deploy can be told from a no-op. The shipped model on both paths is claude-sonnet-5. The open questions of the field test are how often a press earns nothing, and how much of a long thread a brief actually replaces.