Building in public
What we’ve shipped
Qiksy is a small studio building AI-native micro-tools — in the open. Every new tool, real bit of progress and the occasional fix lands here first. No hype, just what changed.
The extension changed its name, because the old one put it on a shelf with nothing on it
It is called Qiksy Bridge now, and the store title says what it does: a browser MCP extension for Claude, Cursor and Codex. The old name led with manual QA, and the page led with it too — so people read it as a form filler and left. The bridge, which is the whole point, was the hundred and first word; MCP was the six hundred and sixty-eighth. We measured before renaming rather than after: the store search for "qa copilot" carries sixty-two installs across six cards, thirteen of them ours, while the search for "mcp" carries around a hundred and twenty-six thousand. Our own phrases for what we do — "use my logged in browser", "existing chrome session" — return no search suggestions at all. Nobody types them. The front page now opens with the thing itself: an MCP server for the tab you already have open, with your session and your logins, and the honest difference from Playwright MCP, which starts an empty browser and signs in from scratch. Nothing about the product changed, and the extension keeps working with no agent at all. The new listing is with Google for review.
The Legato reference now speaks the twenty-five languages the browser does
The feature reference was English only while the landing beside it shipped in twenty-five languages, and the gap was not a matter of politeness: a screen reader picks its voice from the page’s declared language, so English text under a Polish or Japanese code is read through the wrong phonetics. Somebody could read why the browser exists in their own language and hit a wall the moment they wanted to know how it works. The page also doubled — twelve sections to twenty-two — because a good deal of the browser had never been written down: reading a page with the arrow keys existed only as one line in a table of shortcuts, and copying a piece of a page, the mouse wheel that walks instead of scrolling, the shelf of games, the shop card, the braille setting and the seventeen page fixes for low vision were not there at all. Two faults turned up in the translating and both were the same shape. The browser says «reader» out loud in Russian and the translation wrote the technical loanword instead — correct, and a different word for the same thing than the one the product uses. And the page quotes seventy-five menu items while promising you will find them under exactly that name: agreement ran from 38 % in Japanese to 70 % in Hungarian, so a sighted reader would have checked against the screen in a second and a blind one would have hunted for an item that is not there. Both are now taken from the browser’s own dictionary rather than translated afresh, agreement is 96–100 %, and a gate holds it there.
Copying a piece of a page, without being able to see where the piece ends
Selecting text is a mouse gesture, and every workaround a blind person has for it is awkward: a text cursor whose keys clash with reading, the screen reader’s own markers, or select-all — which takes the menu and the cookie notice too. None of the three tells you what you took; you find that out after pasting it somewhere else. Legato 0.3.84 answers the copy shortcut itself, and only when nothing on the page is selected, so the ordinary behaviour is untouched. Draw a frame with the mouse around a piece and it works out the block from what fell inside — no need to hit the edges of a paragraph you cannot see. Or press S where the piece starts, walk to where it ends, and copy. Then it reads back what it took: a short piece in full, a long one by its first words and its last, which answers both “is this the right piece” and “did I take too much”. While a start is marked, each step makes a quiet click — the mark is alive and the step counted. The same release fixes something the work uncovered: on a page that grew above where you were standing, the down arrow moved you up.
The globe on the Route page did not exist for a screen reader
The planet is the first thing on that page, you can click cities on it and watch a route stretch between them — and to a screen reader it was nothing at all: a canvas marked as decoration, on the grounds that the city names underneath were being read out anyway. Those names were, but the thing itself was not, so someone listening heard “Kyiv to Barcelona” arrive from nowhere. It is now described the way a person would describe it: a planet turning slowly, blue water, milk-coloured land, and no continents or borders drawn on it — one Earth, the same for everyone. The description also names what is missing rather than leaving it to be discovered. And the cities are reachable now: the same ones the globe shows are real buttons, one stop on the keyboard route with the arrow keys moving between them, invisible until focus lands on one. They call exactly the code a mouse click calls, so both ways of picking a route can never drift apart.
Every Legato release that ever reached anyone is now written down
The notes page went from eleven versions to twenty — all the way back to 0.3.52, published on 19 August 2026, which is the first build that reached a person at all. Nothing is missing before it, and the page says so instead of trailing off. Versions that were built and handed to nobody are named and excluded, because they are not part of what anyone has. The biggest entry is 0.3.64 — two hundred and forty-nine changes, and the release where the browser stopped only reading pages out and started having things to do in it: a shelf of games with backgammon built to be played by ear (both dice in one keypress, a refused move that explains itself, network play that Windows and a Mac completed against each other), a family tree walked with the keys, routes that replay a path through a site, and a large-text switch. Forty-six topics and a hundred and fifty-one lines in total, each one traceable to a build somebody actually received.
The lower half of the landing page now uses the width it was given
Those sections ran in a column narrower than the header above them, with the right third of the page empty. They are on the full container width now — the same line the header sits on. The width went to the BLOCKS rather than to the prose: what Windows and what macOS say on first launch now stand side by side instead of one under the other, the three checksums are three cards in a row, and the list of what the browser cannot do runs three across. Paragraphs keep their reading measure of about 65 characters, deliberately — filling 1080 pixels with prose would mean lines of a hundred and fifty characters, and this is a page for people with low vision. So the page fills its width without a single line getting longer.
The lower half of the landing page looked like a column had fallen off
It had two faults and they compounded. The narrow column — six consecutive sections, everything from "How to install" down — was pinned to the left edge of the wide container, on the reasoning that a centred column would make the text jump sideways while scrolling. True, but the price was worse: the whole bottom of the page sat against the left edge with the right third empty. It is centred now, and the jump happens twice, at the two joins, instead of being permanent. The second fault was inside that column: it was 680px wide while the text in it is capped at 68 characters — measured live, 476px — so cards and quote rules ran two hundred pixels past their own content. The container now sits on the width that actually lives in it; the line length did not change by a single character. And one section had a short note beside a tall column of text, leaving six hundred pixels of nothing under it; the note is centred in its column now and reads as the aside it is.
The release notes page now covers twelve releases, not two
It started at 0.3.82 with a note saying the earlier ones had never been written down and that reconstructing them from commit messages would produce something plausible rather than something true. There was an honest way to do it after all: go by the release tags rather than the branch — by what people actually received. So 0.3.72 is absent, because the version was bumped and never shipped to anyone, and the quit-key fix sits in 0.3.83 even though the branch would file it under 0.3.82, because it landed after 0.3.82 was already out. The nine reconstructed entries are deliberately shorter than the two newest: a fault is named, not narrated. Among them — pages freezing for seven seconds, a Portuguese page read with Russian sounds, a screen reader handed the bare word "collapsed" with nothing to say what was collapsed, and Arabic arriving as the twenty-fifth language and the first read right to left.
A release notes page, because a blind tester had no way of knowing what to re-test
Mehdi Malakane updates the browser and then has to guess what changed. He asked for the model NVDA uses: a What’s New item in the Help menu that opens a versioned page, with the version number as a heading so a screen reader’s heading list becomes the table of contents. It is now at qiksy.app/legato/whats-new/ and the menu item opens it at YOUR version rather than the top. It starts at 0.3.82, which is the first release whose notes were actually written down — reconstructing the earlier ones from commit messages would produce something plausible rather than something true, and the page says so out loud. 0.3.83 is on it and is out: the ring menu no longer swallows the quit shortcut, it no longer hides the whole browser on the light theme, and the backdrop behind it is dark enough to see.
A release notes page, because a blind tester had no way of knowing what to re-test
Mehdi Malakane updates the browser and then has to guess what changed. He asked for the model NVDA uses: a What’s New item in the Help menu that opens a versioned page, with the version number as a heading so a screen reader’s heading list becomes the table of contents. It is now at qiksy.app/legato/whats-new/ and the menu item opens it at YOUR version rather than the top. It starts at 0.3.82, which is the first release whose notes were actually written down — reconstructing the earlier ones from commit messages would produce something plausible rather than something true, and the page says so out loud. 0.3.83 is on it and is out: the ring menu no longer swallows the quit shortcut, it no longer hides the whole browser on the light theme, and the backdrop behind it is dark enough to see.
Engine 1.12.0 — the first build an update can actually reach
Published to the registry. It is the first version that tells the tools which version it is, which is what makes the new update notice possible at all: until now nothing on the page could tell a current engine from one installed months ago. It is also the first build whose autostart cannot be left pointing at a directory that gets cleaned — installing with npx used to pin the entry inside the npm cache, and when that cache was cleared the engine quietly stopped starting. Anyone already running an older engine will not be told about this one, because being told requires the version reporting that arrives with it; from here on the notice works. Update it with one line in a terminal: npx qiksy@latest.
On dark backgrounds the accent colour was being used as text, and it was too dark to read
A palette has two blues in it, not one: a fill colour, judged against a lower bar because nobody reads a button’s background, and a text colour that has to clear the full contrast threshold. Across the Route and Offer pages the fill colour had been used for text in a dozen places — step numbers, badges, links in the product strip, the duration label in a timeline — and on a dark background it landed between 2.8 and 4.4 against a requirement of 4.5. Every one of them now uses the colour meant for text, which lightens in dark instead of darkening. The worst of the set was the product name beside the logo: white on a light blue pill, 1.76 to 1, the first thing anyone reads on the page. Its fill had been switched to a light one without switching the ink to match. And the check itself got better at explaining: it already knew the two colours and the exact ratio for every failure and printed neither, so fixing one started with half an hour of hunting through tokens. It says the numbers now.
The walkthrough’s steps were invisible until their animation had played
Each step of the demo on the Route page faded in, and it did that by starting at zero opacity and animating up. That is fine while the animation plays — and the trouble is that "while" is an assumption. A tab that has been throttled, a machine saving battery, a mistake in a neighbouring rule: any of those and the step never becomes visible at all. The accessibility check caught the page in exactly that state and counted 392 elements with no contrast across fourteen pages — text on top of invisible text. The movement stayed; the fade went. It looks the same and it can no longer leave content that nobody can read.
Updates to the local engine were reaching nobody who had already installed it
The engine runs on your own machine, and once it was installed it stayed exactly as it was — for good. Three separate reasons, each enough on its own: the autostart entry pins the absolute path of the copy that installed it and runs that file forever; there was no version check anywhere, not in the engine and not in what it tells the page; and the install command only fetches a newer build when somebody types it, which the person who set up autostart never does again. So a published fix sat in the registry and never travelled. The engine now reports its own version, the page knows which one it expects, and when they differ it says so once — a line you can dismiss, and a permanent one in each tool’s settings for when you come back to it. It still never updates itself: it is holding running searches and your Claude sign-in, and software that quietly replaces itself underneath a search in progress will one day cost somebody an hour with no explanation. Two things that made this worse are gone too. Rebuilding the engine refreshed its tools but never the supervisor that starts them, so a fix to that half could not reach an installed engine at all. And for anyone who installed with npx, the autostart pointed inside the npm cache — a directory that gets cleaned — after which the engine silently stopped coming up and the tool simply said the local server was not running.
The live search feed flickered a new border into view every second
While the agents hunt, the feed adds a line every second or two — and each new line arrived carrying two fresh borders with it: a divider above itself and a box around its icon. On a still mockup that reads as a tidy grid. In a feed that is actually moving it reads as flicker, in the corner of the eye, exactly where someone is waiting for a result rather than admiring the layout. Both are gone; the one piece of movement that means something — the pulse on the line being worked on right now — stays. The feed also ends where it should now, with no doubled line at the seam where it meets the results below, and the button that adds a country is the same height as the country chips it stands beside, instead of eight pixels taller than the row it belongs to.
Opened outside the studio, Route and Offer looked like somebody else’s products
The colour you pick applies to everything — background, borders, every active element — and it was reaching only the pages the studio shell draws. Open the same tool on its own address and a different palette took over: not a worse arrangement of the same colours, a different set entirely, written years apart and hardest to read in dark mode. Both tools now carry the colour, the light/dark choice and the classic/modern style outside exactly as they do inside, and they carry it from the first painted frame rather than repainting it in front of you. Two things that only existed in the shell came out with it: how much of the Claude subscription is left — the session and weekly rings, with the real figures Claude itself reports — and whether the agent is answering at all, which Offer had never shown anywhere. And because four appearance switches in a row had grown wider than the tool’s own menu and had started colliding with it, they now live together under one settings button, leaving the header to say what a working tool should: is it running, and how much is left.
Legato 0.3.83 — the ring menu you could not get out of
Open the ring menu with the right button, then try to close the browser: nothing happened, and the menu would not close either. The ring lives in a frameless window of its own that takes the keyboard, and application-menu shortcuts were not reaching past it — Escape worked, because the menu handles that itself, but Command-Q did not. Measured with a clean control: same window, same state, the ring open and Command-Q does nothing; press Escape and the same key quits. Fixed for all five of our own windows — the ring, the menu card, the tour, the account card, the extensions card — because all five had the same hole, and it quits the ordinary way, so the session, history and downloads are written to disk exactly as on a normal quit. Closing the window now takes the ring with it, and whatever asked for the menu gets its refusal: a site that had requested to share your screen used to wait forever. Two things about how the ring looks, both reported from a real screen: on the light theme it was painting a solid sheet over the entire browser — no toolbar, no tabs, no page, just a blank field with the circles in it, measured at full opacity across the whole window; and the disc behind the circles was tinted with the theme’s own background, which on a dark page is dark over dark, so it was not visible at all. It is darkened with black now, which works on any page, and the page still shows through. And the Help menu has a «What’s New» item that opens the release notes at YOUR version — the update channel has existed since 0.3.20 and had never once said what it delivered.
While the engine was being checked, the status pill said nothing at all
The pill in the Route header had two states — connected and not connected — and the first seconds of every page load belong to neither: the answer has not come back yet, so nothing is known. The label was simply left empty in that gap, which meant a grey dot with no word beside it, and the honest-looking alternative would have been worse — “agent disconnected” announces a fault that may not exist. The gap is longest right after a reload, because that is when the engine is still starting the Claude CLI. There is now a third state that says what is actually happening: connecting, with the dot breathing quietly, a button that does not offer to repair something that has not broken yet, and nothing promised to a screen reader that the button cannot do. The pulse stops for anyone who asked for less motion.
The header stopped talking about money and started answering the question people ask
On a subscription the dollars in the header meant "this is what the work would have cost" — an answer to a question nobody asked. What people actually want to know is how much of the plan is left. So the money is gone and two rings took its place: the current five-hour session and the week, with the reset time for each. These are Claude’s own percentages, not our estimate. There is no usage endpoint a subscriber can call, but the binary answers its own /usage locally and that read costs nothing, so nothing is invented and no request is spent asking. They refresh on their own every two minutes, and a screen reader is told when the state changes rather than every time a digit does.
Signing out of Claude threw you onto an installer for an engine that was already running
Route asked the machine one question — can you run the agent — and treated every answer that was not «yes» the same way: by showing the install screen. But an engine that is installed, running and merely signed out answers that question with a polite «no», so a person who signed out was handed a «Download for macOS» button and the line «we will connect as soon as it starts», on top of an engine that had already started. That is a dead end in the literal sense: the screen waits for an engine to appear, the engine has appeared, and the only place in the whole app where you can sign in to Claude sat behind a branch you could no longer reach. The other half of the same trap was in Settings, where the account card could do exactly one thing — sign out — and offered it to people who were already signed out: press it, confirm, hear «signed out», see nothing change. Somebody whose limit had run out wanted the opposite thing, and there was no way to do it from there at all. The button now says what will actually happen: not connected — «Sign in with Claude», which starts the Anthropic sign-in on this machine and waits for the engine to come back green; connected — the old «Switch account», still behind a confirmation, because signing out takes Claude away from everything else on the computer. The wording comes from the shared dictionary rather than new strings of its own: the same button is already named there in seven languages for the gate, and two editions of one sentence drift apart.
Settings could sign you out of Claude but never back in
The account card in Route’s settings had one button and it always meant the same thing: sign out. That is the right offer when an account is connected, because the Claude CLI has no switch and changing account really is a sign-out followed by a sign-in. It was the wrong offer to everyone else — someone whose spending limit had run out, or who had already signed out, was invited to sign out again, asked to confirm it, told it had worked, and shown no change at all, because there had been nothing to sign out of. Signing in from settings was not possible in the first place. The button now says what will happen: it offers to connect an account when none is connected and starts Anthropic’s own sign-in, and it keeps offering to switch when one is.
Signing out of Claude threw you onto an install screen for software you already had
Route asked the machine one question — can it run the agent — and treated every answer that was not yes the same way: it showed the page that explains how to install the engine. But an engine that is installed, running and simply signed out answers that question with a polite no, so anyone who signed out of Claude, or never signed in after installing, was handed a download button and the line "we connect the moment it is running" — over an engine that was already running. It was a dead end in the strict sense: that screen waits for the engine to appear and it had already appeared, and the only screen in the whole app that carries the sign-in — the button, the link and the field for the code — sat behind a branch the code could never reach. Route now separates the two answers: no engine, and here is how to get one; an engine that is signed out, and here is the way in. Offer was repaired this way in July and Deal was never wrong; Route was the one left behind.
The one button on two landing pages that opens the tool opened nothing
On the Offer and Route pages the main call to action pointed at the hub with a hash — and a hash here is an id in the app registry. Both products had been renamed, so the id in the link no longer existed: the hub looked it up, got nothing back, and quietly stayed on its own home page. No error, no 404, nothing to notice — the button simply did not do the one thing it exists for, and it had been that way since the rename. The same defect was found on Route earlier the same day and this is the rest of it. The links now go straight to the product’s own prerendered address rather than through the hub, which also removes a flash that was there even when the id was right: the hub would paint its home page first and only then navigate away.
You could update the browser and have no way of learning what changed
The update channel has been in Legato since 0.3.20. What it never had was a way to say what it had just delivered — the menu item installs the new version and then goes quiet. For a sighted person that is curiosity; for a blind tester it is work with nothing to check it against. Mehdi Malakane, who tests through AppleVis, asked for the fix in one sentence and named the model himself: NVDA’s. So there is now a release notes page at /legato/whats-new/, and a «What’s New» item in the browser’s own Help menu that opens it. The structure is the whole design: the page heading names the page, every VERSION NUMBER is a heading one level down, and the topics inside a release are one level below that — so a screen reader’s heading list is the table of contents, and jumping between releases is one keystroke repeated. The menu item does not open the top of the page either: it builds an anchor from the version actually installed and lands you in your own release. We already had a changelog — this one, the page you are reading — and it is the wrong instrument for that reader: it runs by date across every product, Legato appears in it about ninety times, and no heading names a version, so answering «what is in 0.3.82» would mean listening to the whole feed. The new page starts at 0.3.82 and says so out loud rather than pretending to a history it does not have: earlier versions shipped with no notes written down, and reconstructing them from commit messages now would produce something plausible instead of something true — and this is the text people re-test against. The menu string went into all twenty-five dictionaries in the same commit, Russian and Ukrainian by hand: the menu is rebuilt from scratch on a language change, and one English line in someone else’s menu is a dead stop for a person walking it by voice. The page also carries the NEXT release already, marked in a sentence as not yet shipped — preparing before the update arrives is the whole reason it was asked for, but somebody landing there after updating has to be able to tell «I have this» from «this is not out yet» in one line, so it is said in words rather than shown with a badge or a colour.
The page promised three minutes and blamed a finished trip for someone else’s failure
Three places where the interface said something other than what was happening. The red plate above a trip took the LAST job of any kind and printed the wording written for a failed search — «the agent ran out of time, try again or narrow the trip» — while the search had long finished and eight options were sitting right below it. What had actually timed out was the how-to-book lookup for ONE of them, which has a clock of its own. There was nothing to narrow, and a finished trip was being painted as a crash; the plate now names the option it is talking about and leaves the results alone. Then the numbers: «about 3 minutes» under the search button was met by NONE of the fifteen runs in the log — median 8.2 minutes, spread 6.6 to 18.2 — and «usually under two minutes» on the booking lookup was met by 2 runs out of 14, median 3.8. Both are now the measured figures. That is not admitting to being slow, it is refusing to promise what we cannot keep: at the third minute of a three-minute promise a person starts believing the tool has frozen. And the last one is about language. The contents of a trip — the options, the summary, the boards — are written by the agent during the run, in the language of that run; switching the interface language moves the labels around them and deliberately leaves that text alone, because translating what an agent already said would show a retelling instead of the answer. The product never mentioned this, so a Ukrainian trip under a Spanish interface simply looked broken. It now says so twice: a quiet line on the card explaining that the contents are in the language of the search and that a fresh search brings them over, and one explanation at the moment of switching — shown only when the open trip really does contain the agent’s text, because warning about something that is not on screen teaches people to dismiss warnings unread.
Access is a page now, not a workbench — and it changed colour
The audit workbench is gone from this site. It was five screens of a tool nobody was meant to use here: the audit is work we do, and the instrument for doing it now lives in Jig, where there is an engine, projects and roles for it. What is left on qiksy.app is the page that explains the service — which is what somebody arriving here actually wants. The colour moved too, and by measurement rather than taste. Access and Check were literally the same teal, with Jig, Route, Shift and Deal a few degrees away: six products sharing one hue, so the accent had stopped telling anything apart. Red was tried and dropped for a specific reason — its hue sits one degree from the red the report uses for the instrument’s own mark, and the single red anomaly on the page would have become a shade of the brand. Green means «passed» in the report, which is a strange thing to paint a product that sells finding what did not. Plum sits in the one arc of the palette nobody else occupies, and clears the contrast threshold with room to spare — on a page that sells accessibility audits, its own page passing its own audit narrowly would be the wrong kind of close call.
Route checks the paperwork before you pay, not after
The trip you book can be the one you are turned back from. A passport that expires before the return flight; a Schengen destination that wants three months of validity after you leave, or six months in most of the rest of the world; a traveller who is still seventeen on the day of departure; a departure date closer than a visa appointment usually takes. All of that is arithmetic on dates you have already typed, and it used to surface — if at all — in a checklist generated after the booking. It now stands on the itinerary, before the payment step, because whether the passport is valid decides whether the person flies at all. What it deliberately does NOT do is rule on whether you need a visa or a vaccination: that depends on citizenship and on the whole route including transits, and the cost of a confident wrong answer is somebody stopped at a border. So instead of a verdict there are sources — CDC and WHO, both opened and checked. IATA’s Travel Centre is not among them: it answers a real Chrome with a Cloudflare interstitial and a 403, and a link that turns into a robot test for half the people who follow it is worse than no link at all. The first screen now asks whether this is business or leisure. Border rules are shown to everyone either way; the region’s recommended vaccinations are offered only on a leisure trip, because a «check your shots» panel on every business trip to Barcelona devalues itself and the warning beside it. Health is raised at all only for destinations where a certificate is genuinely asked for at passport control.
The auditor’s workbench has left the site
Qiksy Access is one page now: what an accessibility audit is, what it costs, what you get back. The workbench — the register of states, the templates, the report builder — moved into Jig, where there is an engine, projects, roles and a door an agent can work through. On a storefront it was in the way: somebody arriving to find out what an audit even is landed on an empty desk with a «new audit» button. Access sells the WORK, and the tool that work is done with had no business standing next to the price. With the workbench gone the product is also open to everybody: it had been admin-only and kept off the launcher for exactly one reason — the tile promised a click it could not honour. What stayed in that folder is the report builder’s source, and a README saying so, because Jig carries a copy of it.
The borders were different colours because they were transparent
The line down the rail, the line under the header and the lines between the chat columns all come from one token, and they still came out three different colours. The cause was not three tokens: the line was a translucent layer, so it took the colour of whatever lay under it — frosted glass under the header, the page under the rail, its own surface under a column. One colour over three grounds is three lines, and no amount of adjusting the percentage repairs that. The paint is now mixed INTO the ground rather than into nothing, in both styles. The theme still shows through — the tint comes from the accent, so azure reads blue, violet reads lilac, garnet reads red — and it no longer washes out over glass. The same change made the third step opaque as well, which is not cosmetic there: that step draws the outlines of inputs and buttons, where the contrast is set to 3:1 for WCAG 1.4.11 and a transparent outline over glass was falling below the threshold. Then everything except that step went to half strength on the light theme, which is where the lines were loud; the dark theme is untouched. And the Access icon lost the ring around the figure — the ring was read first and the arms inside it collapsed to a stroke, while the product header was showing a different icon from the rail for the same product.
The accessibility audit is now free — you pay for the code work after it
We were selling the diagnosis twice: a report, then a second report about how to fix the first one, with the remediation itself in the smallest print on the page. That is inverted. The audit now costs nothing — every page type and every state, behind the login included, and the report is yours whether you fix it with us, with somebody else, or not at all. Remediation is priced per state ($120, less above 25 and above 100, minimum 20 states), acceptance is a round walked by hand and by voice by a blind specialist, and there is an hourly rate only for work outside the register. Not per hour for the fixes: one change to a design token repairs every page of its type at once, and billing that by the hour would mean charging less the better our tooling gets. The sample reports doubled in length, and it is the sections that grew rather than the prose: what states were actually opened, every page template with the defect that repeats on it, the keyboard route, the five checks no scanner can answer, an inventory of third-party frames with what to request from each vendor, a 30/60/90 plan and a draft accessibility statement. The audit of our own site came off the gallery — every finding in it was fixed the same day, but on a storefront «13 critical» is read first and «fixed» second. Two new illustrations, and the one on the first screen is the point of the whole page: a caret walks a page fragment while the line underneath prints what a screen reader announces, and on the button with no accessible name that line goes empty. Both stop moving under prefers-reduced-motion and both come to rest showing the defect, not the happy frame.
The button that opens Route was opening the storefront instead
The link still carried the product’s old name, so the hub could not find that id and quietly showed its own home page — the one button whose job is to open the trip planner went somewhere else. Fixed. Three more things on that page, all of which had been true for a while: the route boards are no longer buried at the bottom but explained as their own section, because they answer a different question (what runs this route at all — one answer for everybody, so it is computed once and asks you for no date, no account and no engine of your own); the page now says out loud that running the agent needs a PAID Claude plan, which it had never mentioned; and the tab title finally comes from the dictionary instead of being baked in, so the Ukrainian page no longer announces itself with an English title — a screen reader was naming the tab in one language and reading the page in another. The «copy the install prompt» button also used to rename itself to «Copied», and a label changing under focus is not announced: somebody using a screen reader pressed it and had no way to know whether it worked, on the one step without which the engine cannot be installed.
The «back to Qiksy» button on the Route pages led nowhere
The one control whose entire job is to get you back into the studio was pointing at an address that stopped existing when the app was renamed — on all seven language pages. Google found it before we did: Search Console mailed twice overnight about pages it could not index because a link 404ed. Fixed, and the build now refuses to ship a page whose internal links lead anywhere that is not in the deploy. That check was simply missing: the page rendered, its bundle was its own, its images resolved — only the link was dead, and nothing was looking at links.
The accessibility audit is free now — you pay for the repair, not the diagnosis
The old ladder sold paper twice. An Access Report was a verdict on what is broken; a Fix Pack was a second document about how to fix it, and it said in as many words that we do not go into your repository. The actual repair sat underneath the prices as a footnote. That is backwards, so we turned it around: the audit costs nothing — every page type, every state, and the report is yours to keep even if you fix it yourself or never fix it at all. What is paid for is the work: changes in your source, a round of acceptance with a blind specialist who actually uses a screen reader, and support after later releases. There is deliberately no price on the repair here, because the size of it comes out of the free audit, and naming a number before anyone has looked at your site would be a guess.
A trip card showed «Event: {name}» instead of the event
The badge on a trip card printed the raw placeholder rather than the name of the event. Route passes values into a phrase as a function, and this one line had been written as a plain string, so the value handed to it was dropped on the floor — in all seven languages. Fixed, and an ampersand in an event name no longer arrives doubly escaped.
Jig 1.4.1 — Enter now sends a form, and your own project instructions are read
Two of these matter more than a version number. Enter pressed in a field did not submit the form: the key went in, the reply said it had worked, and nothing happened — which meant the one tool built for accessibility work could not test the way a keyboard user actually sends a form. It does now. And a project folder that carries its own instructions — a CLAUDE.md, a set of skills under .claude/skills — is finally read: those files were invisible before, cut off together with the settings that can carry hooks. Hooks are still not loaded, and never will be: a hook is a shell command, and somebody else’s repository does not get a terminal on your machine. The text is read as text. Also in this build: a site behind a bot shield can be mapped at all (it used to come back empty), the conversation is written to disk while a run is going rather than only after it, and closing the window no longer leaves an engine running behind it.
Legato 0.3.82 — and the Windows installer is not signed yet
Three installers for this version: macOS on Apple silicon and on Intel, both signed and notarized by Apple, and Windows. The Windows one is NOT signed — our code-signing certificate has been paid for since August and is still stuck in validation. Windows will therefore show its blue «Windows protected your PC» screen, and getting past it means pressing «More info» and then «Run anyway». We would rather say that here than let you meet it without warning: for somebody using a screen reader that screen is a dead end, because nothing on it announces that a second button exists. If you are on Windows and cannot get past it, the previous signed version still works, and we will replace the file the day the certificate arrives.
A seat used to mean one more person you were allowed to help
In Qiksy Offer a seat bought one more CANDIDATE. So a recruiter with ten job seekers paid for ten seats, and a recruiter with a budget for four had to decide which six people to turn away. We were charging money to make somebody say no — and charging it for something that costs us nothing, because the searches run on the customer’s own Claude plan and never touch ours. We were rationing what is free to us, and the rationing landed on the person looking for work. Qiksy Route had the opposite fault: no seats at all, so a travel agency with five agents paid the same $290 as one person planning a family holiday, while that same five-person agency in Offer paid five times over. One kind of buyer, two contradictory logics, and neither of them measured what the customer actually gets. Both now count the same thing: a seat is a PERSON WHO DOES THE WORK, not a person who is helped. One licence carries as many candidates, clients and travellers as that person can carry; you pay for how many people at your company use the tool. Nothing about this needed inventing — the licences worker has enforced exactly this axis since August, a seat being one person with three machines, and reassignable. We were simply selling a different thing from the one we were enforcing. Offer’s prices did not move: $129 a year for one person, $99 per seat from two, with the volume steps unchanged — only what you get for them did, and it got larger. Route gains Team at $229 per seat from two, stepping to $159 from ten seats, $109 from twenty-five and $79 from fifty, and the single-person year stays at $290. One trap surfaced while making the change and would have shipped silently: with the candidate cap lifted to unlimited, the old line that let a Team licence RAISE the cap started LOWERING it instead — a five-seat licence would have returned five where Pro now returns no limit, so buying Team would have made the product stricter than not buying it. A second was caught only by re-reading the finished diff: the sentence describing Offer lives in two places on the pricing page, the card and the prose above it, and with one of them updated the page would have promised unlimited candidates and, three lines higher, insisted Pro keeps the same single one.
A cap of five results is how a search stops offering you a choice
Kyiv to London was coming back with one road: a night coach to Warsaw airport, a Wizz Air flight to Luton, the flight back, the coach back, and a hotel. Five cards. The server kept the first five options the agent returned and dropped the rest, so the second road never appeared — not because nobody looked for it, but because there was nowhere to put it. The overnight train was found. It was mentioned, in one line inside a note attached to the coach: cheaper by about fifteen euros, longer by two and a half hours. A line in somebody else’s note cannot be chosen, cannot be compared and cannot be booked, so from where the customer sits it did not exist — and the whole thing read as a tool that does not know how to connect two legs. It knows. It ran out of room on the first connection. The cap is now derived from how long the road is: five for a one-way hop, eight for a return, up to sixteen for a chain, and the agent is told to give two or three whole competing roads that differ in kind — the fastest, the cheapest, and the fully overland one where it exists — and told plainly that naming an alternative in a note is not offering it. The first screen also asks how you want to travel: plane, train, coach, ferry, as four buttons that turn themselves on and off from the pair of cities. That happens on the machine, in under a millisecond, with no network and no model call: the city list is already loaded for the globe, and the rest is three rules and a great-circle distance. Asking a language model whether a train runs from Kyiv to London would mean a spinner while somebody is still typing the city name, and payment for an answer that follows from geography. Kyiv to Lviv switches the plane off by itself and says why — one country, 467 km, the ground wins door to door. Kyiv to London leaves all four on and says the sky over Ukraine is closed, so “plane” here means overland to a hub and a flight from there. Touch a button and the set is yours; the cities stop overriding it. The last one on cannot be switched off, because an empty set is a paid run with no possible answer. Checking twenty city pairs caught three things the first version of those rules got wrong: London to Dublin lost the coach, which really does drive onto the ferry; Madrid to Marrakesh lost the ferry across Gibraltar and was handed to aviation; and Sydney to Auckland was offered a ferry across two thousand kilometres of open sea, where no passenger line exists. Driving the finished screen in a browser caught two more: the explanation was describing a flight through a hub on a route where the plane was switched off, and the cities were being named in Latin script inside a Russian interface.
The board that cost every customer a run of their own now costs nobody anything
How do I get from Kyiv to Rome has one answer, and it is the same answer for everybody who asks: a timetable does not depend on who is reading it. Until today every customer paid for that answer out of their own Claude subscription and waited about three minutes for it. We compute the boards ourselves now, once, and serve them free and instantly. Twelve city pairs to start; adding one is a line in a list and a command. Computing them rather than collecting them from customers’ runs was a real choice with a real price — roughly $0.41 of our own inference per board. Harvesting would have been free and would have grown by itself, but it would have meant the tool sending its results to us, and “runs on your own subscription, we store nothing” is the sentence this product is built around. The lookup keeps that literally: the engine downloads the WHOLE bundle of published boards rather than the one it wants, so the request carries no information about where anybody is going. Each board is also a public page — qiksy.app/route/kyiv-rome/ — and that is the point rather than a side effect. Somebody searching for how to get from Kyiv to Rome is asking a question we can answer; every landing we own answers “what does this product do”, which is not what they typed. The pages are static HTML with no bundle, no prerender and no hashed asset, so there is nothing on them that can fail to load, and they read the same to a crawler and to a screen reader. They are not orphans either: the sitemap entries and the link grid on the Route landing are generated from the same folder, and the build fails if either drifts from it. Two faults surfaced only because a page was printed and read. The frequency column had been showing the agent’s PROSE while the machine rule sat unused beside it, so a row could hold “odd days” in the data and say “daily” on screen — and the screen would win, which defeats the entire reason the rule exists: nobody should arrive at a station on a day nothing leaves. The rule is translated and printed now, and the prose is a fallback for a rule we cannot parse. The duration column was worse: it showed the FLIGHT leg, “2 h 25 min”, for a route where you first spend fifteen hours getting overland to that airport, with the fifteen hours explained in a note underneath. People read the column, not the footnote. It is door-to-door now, legs included. A third fault never reached a page: the function that decides two spellings are the same city stripped accents from everything, and Ukrainian Київ decomposes into і plus two dots — so it became киів, and a Ukrainian typing his own city name missed his own cache. Accents come off Latin only.
No date is a question of its own, and it now gets its own answer
Leaving the date empty used to be a refusal: the search asked for one and stopped. But “when” and “on what” are different questions, and the second one is the one people ask first — from Kyiv to Rome, what is there, is a train even possible, how long does the bus take. With no date Route now builds a board instead: what runs on that route at all, grouped by air, rail, coach, ferry and car, with the journey time, the frequency and a price range on each line. It is free and it needs no engine key, because a board is about a route rather than about a day, and the same route answers the same way for everybody. Three rules keep it honest. Frequency is stored as a rule rather than a phrase — daily, odd days, even days, weekdays, a list of days, seasonal — because flattening “odd days” into “often” is how somebody ends up at a station on a day nothing leaves. A price is a range and never a single figure with a button beside it: the board has not seen one live seat, and “from €60” is the outer limit of what it may claim. And what the agent could not find out is printed in its own line at the bottom, because a short board with a stated gap is worth more than a full one that filled the gap in. The board also lives in a separate field of the trip from the options and is deliberately drawn unlike an option card — no frame, no big price, no right-hand total — so a board row cannot grow a “Book” button by accident. That was not a matter of care: separating them makes the mistake impossible instead of unlikely. The single button on the board leads to a date, not to a purchase. Two things after that were found only by looking at it. With no date at all, the trip header printed a calendar icon and then a separator with nothing in front of it — visual litter, and to a screen reader the sentence “calendar, dot, one way”. It says “no date yet” now, in all seven languages, which fixed the header, the trip card and its spoken label at once. And two paragraphs of the same kind sat under each other at wildly different line lengths: the intro was held to a reading measure and the agent’s summary was not, so on a wide window it ran to 140 characters a line. All four blocks of prose on the board share one measure now; the table rows stay wider, because they have a price at the end and the eye follows the column.
A captcha is a wall for a blind tester, and we stopped pretending otherwise
A run that walks into a «prove you are human» page used to keep walking. It read the verification page, filed findings about it, and the client got a report about a site nobody had looked at — worse than an empty report, because it looks like work. Jig now recognises the wall, stops, says which kind it is, and asks in the chat instead: pass it yourself, tell me what it is and where, or there is no check here. «What is it, and where» counts the Tab stops to the check, or says plainly that it sits in a frame of its own and cannot be counted to. For a grid of pictures it looks at the nine squares and names what is in each; then, as you move the mouse, it calls out the square under the pointer by row and column with what is drawn on it. What it never does is answer the challenge. That is not a policy we could relax later: the challenge question goes straight to speech and never reaches the model, the tiles arrive already cut, and there is no code anywhere that presses a square. A person who cannot see the grid can now work it with a mouse, the way a sighted person does, and the site is still being asked to trust a human — because it is one.
A key that says what is on the screen
The accessibility tree tells you what a page is BUILT of. It cannot tell you how the page LOOKS, and «the text sits on top of the picture», «the button is off the edge» and «this is an image of a table, not a table» are all questions about looking. Option-I photographs the open page and reads it back in reading order, in the interface language, and puts the same text into the chat so it can be re-read later. It runs on the tester’s own Claude subscription and the picture never goes to our cloud. It works in every profession, not just the accessibility one. The first version of it shipped nowhere: we bound it to Option-D, which already opens the per-page tool, so the function was never once called — while the keyboard list promised it. That is the expensive kind of bug for somebody who cannot see: it does not break the window, it breaks trust in the list you learn the product from. There is now a build gate that counts the claimants for every Option-letter across all three files that hand them out, and checks in the other direction that every key the list promises is handled by somebody.
The client report was signed by somebody who did not sign it
The document a client pays for named an evaluator it had inferred, counted the same defect several times over, and let raw markup entities through into the text, so a finding could reach the client reading «the "Send" button». Three separate lies in the one artefact that leaves the building. The signature line now carries only a name somebody explicitly signed with, and a separate line says which machine ran it — two different facts that were being collapsed into one. Duplicates merge on the criterion and the element together, so the same broken control in two places still counts twice and the same control found twice counts once. And auditing a folder on your own disk works: a local page was refused by nine separate doors in the code, each with its own hand-written test for what an address looks like, and eight of them had never heard of file://. There is one predicate now. Alongside it, the funnel stopped eating what you say to it: send a link while it is still asking its questions and the link stays in the chat as a queued task instead of vanishing, and several tasks thrown in at once become a checklist with a state on each line rather than a race. Dictation moved onto the machine and got faster — measured against the same recogniser without the change, in the same conditions, not against a number we liked.
Booking no longer starts by opening a browser you did not ask for
Pressing «Book» used to launch a Claude agent with a browser attached, and when the Qiksy extension was not connected the product opened a visible Chrome window of its own. For a sighted person that is an odd flash. For a blind person it is a window that appears outside the focus, announces nothing, and immediately asks for a system permission they cannot see — the owner’s words: «they will not understand that some browser opened somewhere and some allow needs confirming». That branch is gone. The product never opens a browser window of its own again; filling a supplier form automatically is now a switch in settings, off by default, and it works only through the extension in the browser the person already has open. Underneath, the honest path was already written and hidden: a second worker that uses no browser at all and pulls the supplier’s phone, the languages they answer in, chat, email, address, opening hours in YOUR clock, the ordering steps, where you pay and the cancellation terms. It ran only from a button, the button appeared only after everything else had failed, and the result sat in a collapsed block called «Other ways to order» — the main path of the product named as the alternative one and kept as the fire exit. Now the collection starts by itself after a search, the block is called «How to order #N» and is open whenever there is something to order with, and the card leads with one action that never opens a browser: call, or a letter with the subject and body already filled in, or copy the number and the text for chat — chosen by which languages the supplier answers in. The link to the supplier site stays, last, and says out loud that it opens a separate tab. On the way there we found nine buttons that were drawn, pressed, and did nothing at all — among them the only trigger of that no-browser path, both «Copy» buttons, and «Stop search», which left a running trip with no exit except deleting it. All nine had one cause, so the hand-audit that missed it twice in one day is now a build gate. A screen reader on a real Windows machine then caught two more that no eye can see: a note telling the person to press «Edit» next to a button called «Pick who is going», and a trip header that ran two facts together into the non-word «one waytransfer». And a group booking quietly lost people: the form snapshot keyed every tick box by field name, and the «who is going» boxes all share one — so a family of two came back as a family of one, or of three, with nothing said aloud either way.
We took it somewhere Booking does not work, and the real data broke it
Testing this on Vienna to Madrid proves very little. So we pointed it at Bulawayo to Hwange in Zimbabwe and Kigoma to Mpanda in Tanzania — rural routes where the international aggregators simply are not present and half the operator sites answer an automated request with a 403. The agent did well: it found phone numbers with the page they were printed on for four options out of five, said plainly which sites it could not read and why, invented nothing, and — having read the note on the traveller’s card — rejected the cheaper overnight coach on the grounds that arriving at 04:52 is not safe for a blind passenger travelling alone. Then it broke our code, which is the whole reason for going there. Rural timetables are not published, so a real answer comes back as «around 14:30», or as «daytime, exact hour unconfirmed». Our clock parser assumed a clock. The arithmetic downstream turned that into NaN, the number vanished into null on its way through JSON, and the STRING «NaN:NaN» survived all the way to the person: a screen reader read out «you will be there around N-A-N colon N-A-N» on the one line that answers «when do I reach the guest house». Four blind testers walking the real result found it independently; it was the only defect all four filed. Alongside it, the gap before the meeting quietly became empty on exactly the cards where the summary promised «a whole evening before nine in the morning». Both are fixed, and the rule underneath them is the interesting part: silence is not a safe default. «We could not work this out — the arrival time is only approximate» is an answer; nothing at all is indistinguishable from «everything is fine». Every travel card now carries exactly one line about the meeting: you make it, it is tight, you are late by this much, or we could not tell. Twenty-nine more dead ends came out of the same walk. Recording a booking you made yourself by voice existed only after the agent had already failed — useless on a route where tickets are sold at a bus station counter and there is no point running an agent at all. The sentence to say on the phone had the same condition, while the facts for it sat on three different screens. WhatsApp was in the data and in the ordering steps — «call or message on WhatsApp» — and nowhere in the interface: not one wa.me link existed in the whole app. Cancellation terms were silent on four cards out of five, because «not checked» was treated as a reason to say nothing rather than as the answer it is. An estimated price, worked out from neighbouring fares because the exact one is not published, was spoken as a firm figure, with the caveat arriving several lines later — and at a cash desk the difference between «$20» and «about $20» decides how much you draw from the machine.
Where the tool used to end outside itself, and a page that rebuilt itself once a second
Seven specialists walked the trip tool — corporate and agency travel bookers, two high-end tour operators, a transfer organiser and two screen-reader experts. Three of them independently filed the same thing as their number one blocker, and they were right about it. The page that shows a trip carries a fingerprint whose job is to skip a repaint when nothing changed; during a search it could never match, because the string being compared carried a stopwatch that ticks every second, a fact that rotates every twenty-five, and the tail of the agent’s log. So the whole trip page — hero, pipeline, the options found so far — was replaced once a second for the entire multi-minute run. For a sighted person that is a flicker. For somebody reading with a screen reader it is impassable: the reader builds its own buffer from the markup, and replacing the DOM resets it along with the reading position. Reaching the payment button that way is not slow, it is impossible. The three moving values are now patched as text, which the buffer survives. Then the options board itself: four roles found, separately, that it had exactly one heading — the hero. Transport, Stay, Transfer and every leg of a chain were rendered as plain divs with a colour per kind, so the eye got the structure and the ear got nothing; the fastest way to move around a long page, jumping by heading, did not work at all. A booking filled in one passenger out of three and no line anywhere said so. The confirm dialog and the report now name who is going. «You would not make the meeting on this one» was printed on perfectly good options, because the meeting field kept its date and the code read only the clock: land at 22:40, meet at 10:00 the next morning, and the arithmetic condemned the flight by fourteen hours. A false accusation is worse than silence — people throw away what suits them. And the client proposal, which is the paid deliverable, turned out to be a poorer product than the screen it was taken from: a fifteen-leg door-to-door chain reached the client as three unordered buckets, there was no total anywhere, the honest «what we could not find» was never rendered, after payment it still invited you to pick an option, printing it to PDF produced a blank first block, and in any language beyond three it silently became English.
When the supplier’s own site cannot be used at all
A question worth asking out loud: what happens to somebody who cannot see, when the hotel or the taxi company on the other end has a site their screen reader cannot touch? Until today the answer was that the tool quietly stopped being useful. The agent would fill in what it could, hit a captcha or a sign-in wall, and hand back a link labelled «continue manually». The reasons that page stopped the AGENT — a captcha, a modal that never takes focus, a booking widget with no labels — are precisely the reasons it is impassable for a screen reader. We were walking somebody to the door and pushing them into a wall. Six specialists went through the code on this one question, two of them blind. Fifty-nine findings survived an adversarial check, and all six arrived at the same dead end independently. So the agent now takes the offline path BEFORE it gives up: at that moment it is standing on the supplier’s own page, and that is the only moment those contacts are reachable — afterwards the card has no internet at all. The report gained a heading you can jump to, the reason for stopping picked from a machine-readable code (six different texts where there used to be one), the phone as a real number in a tel: link and as text, a ready sentence to say on the call with a copy button, what is still left to do, a button that records a booking you made yourself by voice — and only then, last, the link, named honestly: the page the agent stopped on. Two more things came out of it. The product had been calling a captcha a success: the status flipped regardless, so a trip sat in «waiting for payment», the card said «booked», and under a report with nothing filled in there was a button marked «Paid». And every option now carries how to order it AWAY from the site — phone with a status and a source, opening hours converted into the caller’s own clock, address, how you are met, the channels, the steps, the cancellation deadline. Copied character for character from the page, never from memory: a number a machine remembers is a number somebody dials blind.
The same mistake in four places: a colour meant for decoration was doing the work of text
A contrast gate stopped a deploy with 217 failing elements, all on one route — and the interesting part is that we had checked. We had checked the pairs of TOKENS we chose ourselves; the gate measures what the page actually paints, and those are different things. Four of the failures turned out to be one mistake wearing four hats: a tone documented as decorative, judged at 3:1, had been used as INK, where the threshold is 4.5. The duration chip in a leg’s timeline measured 3.47. The default section colour measured 3.89. The per-kind section colours — the amber one that says «transfer» — measured 3.10 as a bold heading. The fourth was the pipeline step we had fixed the day before and filed as a one-off; it was not a one-off. Three more, each its own story. The «recommended combination» badge took its ink from a gold token that this page does not own: the studio shell declares its own amber, so the badge rendered amber on a hard-coded white at 2.08 — the cause was not in the product at all. The line that says «you would not make the meeting on this one» — the single most important sentence on a ticket card — was unreadable in the dark theme, because the danger token it referred to had never been declared and the fallback was a light-theme red at 2.29. And in the classic dark skin the semantic green and blue, the ones that mean «paid» and «found», sat at 4.01–4.08 on their own washes. All of these are defects in the TOOL, not in the page that exposed them: the classes are shared. The tool lives inside the studio, where the gate does not reach; the public page ran its cards past a checker for the first time. Thirty-one failures on the route, then zero. Said plainly, because it matters: axe sees about a third of the standard. Meaning, focus order and keyboard paths are still a human’s job, and that pass has not been made yet. Separately, the product stopped speaking as one role. It used to say «HR enters the card» — in the booking confirmation, in the combo confirmation and in the payment note. That is wrong for an agency, and wrong for somebody arranging their own trip. It now says the card is entered by you, and the setting called «HR timezone» is called «your timezone». The first screen says both jobs out loud: one ticket from here to there, or the whole chain — for an agency, for a company, or for your own trip.
«Try again in a minute» was a lie, and it was covering eighteen different refusals
Press Book on a trip that has no traveller card and the tool said: it did not work, try again in a minute. Waiting would not have helped at any hour — the trip simply had nobody to book for. The mechanism is worth writing down because the cure was worse than the disease. The engine answered in plain Russian sentences, and the interface deliberately never shows the engine’s own words, because English and Ukrainian readers were getting raw Russian toasts. So the interface translated four machine codes and swallowed everything else into one sentence about a minute — eighteen distinct refusals, including «there is no traveller card», «that option is no longer in the selection», «the traveller needs a full name» and «this trip was deleted in another tab». Every reachable cause now has its own code from the engine and its own sentence here, in the reader’s language and with the action in it: «Nobody to book for: this trip has no traveller card. Add a person on the Travellers tab — the passport is entered once and fills itself into the ticket.» There is not one Russian sentence left in the engine’s answers. An unexpected refusal no longer promises that it will pass by itself; it says the engine refused and quotes what it said, which is at least diagnosable. Verified by calling the API rather than by reading the code. The loading screen was fixed in the same pass: it was pinned to the WINDOW, so inside the studio it sat in the middle of the whole screen — exactly half a sidebar to the left of the area it belongs to. It now centres in its own section, and Travel greets you with its own carriage racing on the spot, the same frame the agent draws while searching, instead of a generic three-dot mark. Then the surfaces, judged by four senior designers who were handed four real screenshots (both styles, both themes) rather than a description. The dark ground was raised in LIGHTNESS, not merely de-blued: a card differed from the page by 1.11:1, which is not enough for it to read as an object at all; it is 1.19 now. The light ground became milk — the same lightness, but the red channel above the blue rather than under it, because a de-blued grey is still grey. Three petrol radial washes were deleted outright: they put a different luminance under every card, so no card could sit a known distance above the page; one symmetric horizon replaced them. In the classic light skin the console panel was a GHOST — 1.09:1 against the page with shadows switched off, so its edge was literally invisible; its hairline is 1.41 now. In classic dark two ink tokens were the SAME COLOUR, so body text and captions sounded alike. And two things the council caught that we had missed: the dotted texture in the background was painted in rgba(15,80,80,.045) — a dark TEAL, the last green left on a page where green is banned, and it had survived every token swap because it did not live in a token; and one shell token arrives from the kit at 2.39:1 on the light bar against a 4.5 gate — a live accessibility failure, recomputed by hand before believing it, and now 4.94.
The globe was not flickering in colour — it was flickering in a fill rule, and three rounds of fixes had gone to the wrong cause
The planet on the Route landing changed colour while it turned: continents went white, then the ocean did, dozens of times a minute. Three rounds of work had gone into the palette, the night side, the city lights and the theme switch, and none of it was the cause. The land was drawn as ONE path across all 126 coastline rings, filled even-odd. A coast that passes behind the horizon has to be closed with an arc along the limb of the sphere, and every one of those closures needed a decision: which way round. Get it wrong and the path gains almost a full circle, and even-odd from one extra circle inverts the whole disc — land becomes water. While the globe turns, those closures happen dozens of times a frame. The direction had been taken from the tangent of the coast, then from the orientation of the ring; we built a rig that runs a full rotation of 120 frames outside the browser and compares the share of land on the disc against an independent oracle — a land mask in longitude and latitude, which agreed with the known figure that land is 29% of the Earth’s surface. The tangent rule was wrong on 29 frames out of 120, the orientation rule on 24, both by up to 65% of the disc. So the choice was not nearly right; there was no choice to make. There is no decision now at all. A land mask is built once, and it is built by scanning parallels rather than by filling outlines — which matters, because four of those rings cross the 180th meridian, and in a flat map such a ring draws a chord across the whole width and flips the parity behind it. That is why the first attempt at a mask filled the Arctic with land and lost Antarctica entirely, and why our own first oracle agreed with it: both were built the same wrong way. Now each parallel is cut by the coast where it actually crosses, and the phase is carried down from the north pole, where the answer is known — there is ocean there. Every point of the disc then asks the mask whether it is land. Measured against the oracle: 0.09% disagreement, and the largest change between two neighbouring frames is 1.08%, which is just geography turning. It used to be 34%. Then the colour, because the owner said plainly that he does not like the green: the whole environment is petrol blue now, deliberately pulled toward cyan because Offer already owns indigo and two products a hue apart read as one product in the launcher. Removing the green took six places, not one — four palettes, the kit’s environment accent, the page’s background gradient, a scrollbar, a pipeline step and a hard-coded colour on the product pill in the header. Recomputing every pair against the new grounds turned up five real AA failures, four of them inherited from the teal era: a token used in 47 places, almost all of them body text, at 2.92:1, white text on a tone documented as decorative at 4.05, a signal chip whose ink measured 3.80 on its own wash, a ghost button whose border fell back to a 1.28:1 hairline outside the studio, and — the one that matters most — the route caption under the planet, which sat ON the dark edge of the globe and was marked aria-hidden, so the only text describing the main object of the first screen was read by nobody. It is in the flow under the globe now, in a live region, and it is spoken. axe-core reports no violations in either theme; the keyboard walk closes in 22 steps with all 21 interactive elements reachable. Last, the page stopped illustrating itself. Beside the drawn window with its invented trip there is now one real search, made by the engine on 3 September 2026: Kyiv to Munich with Ukrainian airspace closed, so a bus to Warsaw, the EuroNight Chopin sleeper on to Munich, a hotel, and the same way back — about €465 against a €600 budget, and with the caveat the agent refused to smooth over, that the hotel price is an estimate because Oktoberfest moves it and that the bus alone would arrive four hours after the meeting. It is a real table with row and column headers, so a screen reader hears «sleeper train, Warsaw to Munich, 14 h 14 m, 40 euro» as one sentence instead of columns of numbers.
A critical finding called itself a blocker, and the crawl never admitted where it stopped
We wrote the accessibility auditor a guide and put it in front of seven blind reviewers before putting it in front of a real one. They named six things. Two of them were wrong, and saying so is the point: one reviewer worked out from the text that the page verdict grabs the focus once per page, so a forty-page walk would grab it forty times. Reasonable from the text, and not what the code does — nothing focuses the score line, the re-announcement only fires while the focus is still inside that same panel, and a site walk runs in another process that never reaches the code at all. We had already written the confession into the guide before checking it. The other four were real. The worst of them: the store produces a severity called critical — it is what an axe result of serious becomes — and the severity picker had no such option. A widget handed a value it does not offer shows the FIRST one instead, silently, so a critical finding called itself a blocker and the screen reader said the wrong word. The same level printed as a bare key, sev_critical, in the ticket that goes to the client, in all seven languages. Second: the result of a check rode to the reader as an accessible DESCRIPTION. NVDA speaks object descriptions only when that setting is on, the people most likely to have turned it off are the fast readers this is built for, JAWS treats them differently again, and unlike a live region it fails without telling anybody. It rides in the accessible name now, which every reader speaks in every mode. Third, from the one reviewer using a braille display rather than speech: an announcement is a queue for a voice and a flash for a display — it lands on top of whatever the fingers are reading, and it can be switched off entirely. So anything whose only trace was an announcement now also lands in the conversation, where you can go back and read it: which file an export wrote, which scenarios an import rejected, how many checks the report left untouched. Fourth: the site walk has three ceilings — pages, link depth, wall clock — and named only two of them. The depth cut-off was invisible because the queue simply ends by itself, so «we walked forty pages» read as a census when it was a cut at the second link from the front page. It says so now. Two more found by looking rather than by being told. The library that does the walking declared default limits nobody ever received, because every live caller passes its own — four different sets of numbers across the codebase, and we had already written the wrong pair into the documentation. The dead defaults are gone and a missing limit now fails loudly instead of quietly returning zero pages. And one file declared two different functions under one name; the later won, so a URL that was meant to be shortened to its path was read out in full. Forty characters instead of two words, to somebody listening. Underneath all of it, the thing that made this possible to check at all: the profession had no acceptance test. Five professions, and the three acts that judge them mention four. The one we are handing to a blind auditor was the only one nobody was testing. It has its own act now, and it is built so that it cannot be passed by doing nothing — engine mechanics must be hidden from the auditor and visible to the tester, and the promise to open his checklist must be recorded before the welcome finishes and kept after it.
The accessibility reader was shown an empty panel, because the camera was pointed at the wrong wall
Pick «I audit accessibility» on the Jig page and the picture beside the headline was the Accessibility panel saying «The audit has not been run on this page yet» — an untouched form, two unpressed buttons, and one grey sentence. A frame containing nothing that happened. Two separate things had gone wrong. The panel moved from the bottom strip to the side column on the first of September, and the rig that shoots these pictures still clicked into the bottom, so it pressed nothing and photographed the empty state; it now presses the real button and waits for the result card rather than for a fixed two seconds. The deeper one is that the panel was the wrong subject entirely. It audits ONE open page. The profession is a whole site: mapping it, walking the layers that have no address of their own, filing findings, building the conformance report — and every one of those is a verb the chat drives, not a control in the window. We grepped the window code for the report verb and found zero uses of it. So the auditor now has a frame of his own, and it is the only one in the set where the picture is a conversation: the ask, the findings with the WCAG criterion each one breaks, and the plan of six audit directions with three passed, one running and two untouched. Also fixed, and the reason this took a second pass: the stand server that serves the pages in these pictures had lost an import and crashed on its first line, so the whole shoot could not start. And inside the chat, the tick and the cross in a checklist sat low in their boxes — a line-height equal to the box centres the LINE, not the glyph, and the two have different metrics. They are centred by grid now, like the checkbox two hundred lines above them that had been done properly all along, and a size smaller. One last thing on the same page, and it is the kind of gap you only see once somebody points at it: the four profession chips sat in a two-column grid, and a grid column is as wide as the widest chip in it — so the short one on the second row left forty pixels of air before its neighbour, and the pair stopped reading as a pair. Two real rows of two instead, so the second chip sits against the first the way it does on the row above.
Jig is in the Microsoft Store, and the Windows warning screen now has a way around it
Jig Browser passed certification and is listed. That matters for one specific reason: the direct Windows installer is still unsigned — our certificate is in identity validation — so Windows shows the blue «Windows protected your PC» screen and you have to choose More info, then Run anyway. Plenty of people stop there, and they are right to. A package in the Store is signed by Microsoft itself, so there is no warning at all, and it updates itself. Both routes are on the page now, side by side, each with a sentence saying what it costs you: the Store has no warning but needs the Store; the file needs nothing but shows the screen. We did not replace one with the other — a machine with the Store switched off by policy is exactly the machine that needs the file. The listing itself is free, in all 240 markets, rated 3+ everywhere except Brazil, and the one page of it people read was written against the code rather than from memory. The voice track for the accessibility reader was re-recorded the same day and for a duller reason: we rewrote the transcript and the seven recordings still read the old one, so the page showed one text and spoke another. The first re-take ran fifty-one to sixty-four seconds against a page that promises forty, so it was thrown away and the script cut by a quarter. Thirty-six to fifty seconds now, in family with the other three readers.
The accessibility reader was shown somebody else’s page, and nobody could see it
The Jig landing asks who you are — I test apps, I write code, I write requirements, I audit accessibility — and rewrites the headline, the five windows and the four figures for the answer. The fourth answer was added last month and never worked. The line that picks the override knew three readers and asked one question: is this the coder? If not, use the analyst’s. So choosing «I audit accessibility» painted the green accent over the ANALYST’s page. The copy written for auditors sat in all seven dictionaries and was read from nowhere. It is a table now rather than a chain of questions, so a new reader either has a row or has nothing — taking somebody else’s silently is no longer possible. The text that finally appears is not the text that was written for it either. The old block promised «a report with a score»; the report a client receives has no score at all — we grepped the builder and found none. The score belongs to a different thing, the markup panel. That was the one outright false claim on the page and it is gone. What replaced it is what an audit actually is here: fifteen directions land in the checklist on the first call, findings are filed as you go, and the report is built from them — by WCAG criterion, with the node each finding sits on, the passport of the run beside it, and a plain count of what nobody looked at. Directions a machine cannot judge stay open until a person signs them, and a report with nothing measured refuses to print. Every sentence there was checked against the code before it was written. Three smaller things went with it: the green is a step lighter in both themes (the old one read as acid, and lighting it raised every contrast rather than lowering one), the four profession chips became a 2×2 grid because in a row they were the widest thing in the hero — 743 pixels against a 518-pixel headline — and each chip now hugs its own label instead of stretching to the column, which had «I write code» sitting in a pill three times the width of its words.
Four English pages told screen readers they were in Ukrainian
We ran our own accessibility check over every page of this site — 110 of them, from the sitemap — and it found three things worth fixing. The first is the one that matters. /pricing/, /privacy/, /terms/ and /refund/ are written in English only; the rest of the site follows whatever language you have chosen, and the page was announcing THAT language rather than the language of its own text. So a reader with a Ukrainian interface got an English document declared as Ukrainian, and a screen reader duly read English words with Ukrainian phonetics — technically speech, practically noise. A page now declares the language of its TEXT, and the one phrase on it that IS translated, the skip link, carries its own language marker, which is what WCAG asks for and what we were not doing. Two smaller ones went with it: the investments radar gave the coin name an <h1> on a page that already had one, so a screen reader asking «what is this page» got two answers and no top; and the two silent screen recordings on the QA Copilot page had no names at all — they announced as two unnamed players. The obvious fix there would have been a subtitle track, and it would have been a lie: the recordings have no sound. They have words describing them instead, in all seven languages. Worth saying how the first one hid: fetching the page from outside shows an honest lang="en", because the swap happens after the page comes alive in a browser. Reading the file would never have found it.
A half-written trip survived a language change but not a reload
What you have typed into a trip — the city, the dates, who is going — is kept in a snapshot so that it is not wiped by things which rebuild the screen: switching language, going full-screen and back, moving between the panel and the full page. That worked. What did not was the ordinary case: hitting reload. The snapshot was only ever taken when the screen was being torn down, and a reload does not tear anything down — the browser simply ends the page, and there is nobody left to take it. So the city you had typed was gone. It is now taken when the page LEAVES as well, and by two different events rather than one: the browser’s own leave event is skipped when a page goes into the back-forward cache in Safari and is not always fired on mobile at all, so the second one catches a tab the system killed to reclaim memory. The storage stays per-tab on purpose — the draft lives exactly as long as the tab does, and never resurfaces a week later as «a draft from yesterday that I never started». Checked by doing it rather than by reading the code: typed a city, reloaded, the value was still there. Before the fix the field came back empty.
Walking away mid-search now asks you, and a run nobody is watching switches itself off
Every product in the studio is its OWN page, so clicking the rail loads a different one and this screen goes with it. The run does not: it lives on the engine, on your own machine, and the product promises exactly that in four separate places — close the tab, the search keeps going. That promise stands. What was missing was the CHOICE, and it now appears when you leave a page with agents working: leave it running, end it and go, or stay here. Three answers rather than two, because ending a search and leaving it alone are both things you might want to do — the refusal is staying. We intercept the LINK rather than the browser’s own leave event, which cannot be given our buttons: it would show a generic «Leave site?» with no product name and no third option. Opening a link in a new tab, downloading a file, jumping to an anchor on the same page — none of those count as leaving, and none of them ask. In Offer, ending a run ends it across BOTH industries: you are leaving the page entirely, and a run on the other market is one you would no longer be able to see or stop. The other half of the request was to stop the agents when the site is closed, and doing that literally was the wrong thing. A tab closed by accident — the wrong window, the wrong shortcut, a laptop going to sleep — would cost fifteen minutes of an agent’s work, and the monitoring feature, which people pay for, exists precisely to run while nobody is there. So what is measured is not the closing but the ABSENCE. The panel checks in every two and a half seconds and holds a live channel; if nothing has checked in for ten minutes, there is nobody left to burn quota for, and the manual runs stop themselves with the reason written into their log. Switch tabs, walk away, close it by mistake and come back — your work is intact. The threshold is deliberately generous: longer than any «stepped out» and shorter than a full sweep. Monitoring is exempt, and telling the two apart had to be done honestly — the way a run is started does not distinguish them, so runs born from the monitoring tick are now marked as such. Without that, this rule would have quietly switched off the very feature that is supposed to work when you are not looking.
The agent was reading pages we were guaranteed to throw away, and Travel showed nothing until it had everything
Three architects read the search code today. Two findings shipped, and the first one explains where the minutes went. The agent was told which COMPANIES were already on the board — up to three hundred names — while the server discards a duplicate by its normalised URL. An agent cannot match a page it has opened against a list of names: «Acme Corp» against «Acme Corporation» already misses. So it fetched the page honestly, spent the seconds and the tokens, and we dropped the result in silence. Both lists now go into the prompt, because they cut at different depths: names cut in the search results, before anything is downloaded; addresses cut the one link the server would have binned anyway. The cost was measured rather than guessed — two hundred addresses are about fourteen thousand characters, and a single fetch of a vacancy page puts between two and ten thousand tokens into the context, so one prevented fetch pays for the whole list. Nothing is lost for a job that has CHANGED, either: the exact URL was already remembered forever and already refused the updated record. Re-reading what we know is the link-checker’s work, not the search’s. Route had two separate silences. Its agent streams options as it finds them — but the launch was missing the flag that delivers partial messages, and the parser was anchored to the start and end of a line, so the stream of fragments never matched at all. The person waited two minutes and got everything at once, although the first option had been ready at thirty seconds. And Route had no live channel whatsoever: an option landed in the database and reached the screen up to a second later, because the interface only polled. Both are now as they are in Offer, copied along with the three things that had already cost debugging there — telling proxies not to buffer the stream, dropping frames for a reader that is connected but stalled, and a sync frame so a tab joining MID-RUN knows a run is happening. Also fixed, and caught by a gate rather than by eye: the loading curtain was hiding the landing page’s own heading, because it now waits for the app to say it has drawn, and on a landing page the controller never runs at all.
The thing that shows a page is loading was hidden underneath the thing that hides a loading page
Reload Offer or Route while the agents are working and you got a half-assembled screen: the rail is there, the board is not, and skeleton cards blink in and out. Three separate faults, one after another. The waiting indicator was never visible — not rarely, never. It lived INSIDE the app’s root element, and the curtain that hides a not-yet-drawn app hides that whole element, so the curtain was covering its own indicator; React would also have wiped it on first render. It is an overlay above the page now, removed by hand when the reveal happens. The curtain lifted too early. It waited for React to MOUNT — which takes an instant — while the content is drawn by the controller after the engine answers, a second later or more. Everything between those two moments is the half-assembled screen. Now the app says when it has actually drawn: in Offer at both exits from waiting, the one where the engine answered and the one where it never did, because on a machine with no engine the gate is exactly what has to be shown; in Route after two animation frames, which is the point at which the browser has really painted. There is a six-second ceiling on top, without which a broken bundle would leave someone staring at a loader forever. Measured after the change: Offer holds the curtain 3.0 seconds until the board is ready, Route 1.6. And the indicator itself was a spinning circle, which says nothing about what is happening — a reload in the middle of a run is waiting for WORK, not for a page. Offer now shows a briefcase in flight and Route a carriage, both with the wind streaming past them: the scene stands still and the world rushes by, so you do not have to follow anything with your eyes, and there is no point where it jumps back to the start and reads as a reset. Both are drawn in our own tokens and obey the theme, the style and the studio’s tint, down to the carriage window and the briefcase flap; both stop completely for anyone who asked for less motion, and the frame still reads.
Opening Offer repainted itself in front of you, and it was one letter
Every page here sets the theme, the design style and the tint in a small script that runs before the first paint, so nothing you chose ever flashes as something else. In Offer that script fell over. A variable in the block is called one thing and the line that applies the tint asked for another — a name that belongs to a SECOND boot script further down the file, and does not exist in the first. So the line threw, control went to the safety net, and the net can do exactly one thing: set the style to classic. Which means that on every single load Offer discarded both the style you picked and the tint, painted the first frame as somebody else’s page, and then React delivered the real values after it mounted — the repaint you could watch happen, with the tab labels briefly in the wrong colour. Finding it needed a trick worth writing down: the error is inside a try, so it never reaches the console, and four hundred milliseconds later React has already fixed everything — an ordinary check reports a healthy page. It shows up only with the application’s own script blocked, leaving nothing on the page but the boot code. Measured that way, the live site set the style to classic and no tint at all while the choices were modern and emerald; with the letter corrected it sets both. Route never had this: the same block there is written consistently. Two more things on the same board. While the agents run, the search button is disabled — not broken, just nothing to press — and it was being painted white-on-pale twice over: once because a desk-wide rule dimmed every disabled primary button to forty per cent, and once because the same rule gives primary buttons white ink, which is right on a coloured fill and unreadable on the grey one a disabled button gets. Both halves are fixed and measured: the label now reads at nine to one on the classic theme and ten to one on the plain light. And the source chips — the domains the agent is reading right now — no longer sit flush against the moving progress bar above them.
The page hands you a code, and the field for it was hidden behind a link that called it rare
Signing in to Claude from a tool has nowhere to come back to: the command starts without a terminal, so the sign-in takes the code path — the page SHOWS you a code, every time, not occasionally. Our window had the field for that code folded away behind a link worded as an edge case, and the owner walked the whole path, pressed Copy code, and asked where he was supposed to put it. The field now unfolds by itself the moment it is clear there is no loop back, and it sits ABOVE the waiting line: first the thing you have to do, then the thing we are waiting for. The link stays for the case where a loop does exist. Worse than the layout was the silence underneath it. A sign-in lives ten minutes; after that the command is gone and nobody will accept its code — and the field simply stayed on screen: paste, press Send, nothing. A refusal now names its reason, telling «the sign-in expired» apart from «that code did not fit», with a Start again beside it that raises a fresh sign-in. And the line introducing the window promised the connection would light up here by itself, which on the code path is not true: it lights up when the code is pasted. Rewritten in all seven languages. Two colour faults went out with it. The toast’s backdrop was built from a literal white instead of the card token — invisible on the plain light theme, where the card IS white, and obvious on the classic one, where the card is cream: a cold white slab over a warm page. It uses the card token now, which already knows the style and the tint, so this is the toaster everywhere it appears. The share of status colour in the fill went from five per cent to three, and that is a measurement rather than a preference: on a cream card five per cent of blue pulls an info toast to the cold side of the page it sits on, which is the same complaint in different words. Status is carried by the border and the icon; the fill only whispers it. And the Go button on the travel globe took a plain white for its label, because the token that would have told it otherwise is not defined in every environment — on the dark theme the accent there is light, so white on it measured 2.44 to 1 against a floor of 4.5. It now falls back to the environment’s own colour-on-accent, 6.66 to 1, which is exactly how that pair is declared in the design system.
The tools and your editor shared one login folder, and each was quietly logging the other out
Claude Code keeps its sign-in in a config folder, and the keychain record is tied to that folder. The tools never set the variable that moves it, so they were sitting in the same folder as the owner’s editor — two clients on one refresh token, each renewing it independently, and whoever renewed second was left holding a dead one. This is not theory: Jig walked into it on 20 August, an editor lost its subscription mid-session, and Jig moved to a folder of its own. The tools had been the second client on that folder the whole time. The other half of the same fault was the button: signing out here threw the editor out too, and signing out in the editor took the tools with it. They now have their own folder, one shared by all four — it is one engine and one subscription, and a folder per tool would mean three sign-ins for one account. The old behaviour is one environment variable away for anyone who wants it. The first launch after this had to not look like breakage: the new folder is empty, and a person who is signed in to Claude two windows to the left would read a plain «not signed in» as a broken tool. So the check now reports whether the shared folder is signed in as well, and in that one state the gate says the tools have their own sign-in, it takes one login, and the subscription is the same one. Two smaller things travelled with it. The installer used to freeze the PATH it saw at install time into the startup file — change your Node version afterwards and the engine looks for the command where it no longer is, then reports it missing on a machine where everything is installed and working; the PATH is asked of the login shell now, once per process. And the first screen said the quiet part wrong: while the tools picked up a login that was already on the machine, «nothing else to do here» was true, and after this change it is not. Between a running engine and working software there is now exactly one sign-in, and the setup screen says so in advance — as a third step, with no button on it, because there is nowhere to sign in until the engine is up — instead of springing it on the next screen. The text a person hands to Claude to do the install was corrected in both places it lives, so the instruction and the screen say the same thing.
The board showed one agent’s work under another agent’s name
Two searches can run at once since the end of August — switching industries no longer stops the one already going, which is the whole point of watching a developer hunt and a nurse hunt at the same time. What nobody noticed is that only half of the screen learned to tell them apart. The result cards were filtered by whose search they belonged to, and the code even carries a comment explaining why that filter has to exist. The live feed above them was not. So the board for an IT candidate ran a stream reading «Searching the web: Pflegefachkraft Stellenangebot Bayern», listed liv-pflege.de among its sources, showed a clock and a counter belonging to somebody else’s run — and titled all of it «two agents are looking for work: React / Frontend Developer, AI Systems Integrator». Those two agents were sitting in the queue at that moment and had not made a single request. The owner saw it and asked a reasonable question: why are we searching Germany for a front-end developer. We were not. We were searching Germany for a nurse and writing the developer’s name above it. A person reading that screen could only conclude their profile had the wrong country in it, and go looking for a setting that was correct all along. One condition, the same one the cards already had, now applies to the feed. The second thing on the same screen was smaller and older. While agents run, the search button is disabled — not because anything is broken, but because there is nothing to press. A rule for the whole desk dimmed every disabled primary button to forty per cent, and it caught this one too, so the label and the running clock faded into the button on the light theme. There was already a rule saying this particular button must stay at full strength; both rules had exactly the same weight, and the one written later in the file won. The fix went into the rule that was wrong rather than a fifth rule on top of four, and it was verified by measuring the rendered button in both themes and both styles rather than by looking at it. And the source chips — the real domains the agent is reading right now — sat flush against the loading bar above them, so a moving bar and a list of names read as one block. They are two different statements: that work is happening, and where it is happening. They have room between them now.
The browser could say a page was fine when it had not managed to look at the page at all
A blind tester in Morocco opened a Google web app, met button after button with no name, and was told by the browser: this page is fine, nothing to repair. Reproducing it in the live browser explained the sentence. The page’s main document holds seventy-eight nodes, ONE keyboard stop and zero characters of text; the entire application lives inside an embedded frame with four hundred and forty-nine nodes, thirty-two stops and nearly two thousand characters. Our repair walks the main document only. It honestly found nothing — and reported that as order. Five specialists were asked how this should behave, and they agreed on something that is not a matter of wording: for a repair that cannot see, «found nothing» and «nothing is wrong» are the SAME observation, and a verdict may not fuse them. There have to be three states, not two: looked and clean, looked and repaired, and could not look at all of it. The third did not exist, so everything that did not fit the other two drained into «everything is fine». This is not our invention either — in the ACT Rules format that accessibility checkers are written against, the outcome cantTell sits beside passed and failed precisely for «could not be computed», and returning passed in its place is a breach of the format rather than a stylistic liberty. So the browser no longer has that sentence in its speech. «No repairs were needed here» stays for the eye on the badge and for the report you ask for by key, where you asked; out loud it now says only what it can vouch for — what it repaired, and what it did not get to see. Being able to say the second one required counting: an instrument can only report what it did not look at if it keeps a register of it. Frames that carry real content and were never entered are counted now, and so is a failed measurement — fifteen hundred characters of visible text with a single keyboard stop means blind, not clean. The caveat travels with good news too: «repaired, twelve fixes» on a page whose application sits in a frame is the same untruth as «nothing to repair» on it. The subject of the sentence changed as well, and that was the specialists’ first pick. «This page is fine» is a claim about the world that the browser cannot back up; «I did not go through this whole page» is a fact about itself, true always. It matters most for the youngest users: a child who hears the tool say fine, and cannot make the page work, concludes that the failure is his. What is deliberately NOT claimed here: the browser now tells you honestly that it did not enter the frame — it still does not enter it. On that Google app a blind person now gets the truth instead of a lie, not the application instead of the truth. Going into frames is the next piece of work and it is not one line. Four smaller things shipped with it, each found by somebody’s hands rather than by a check. A file picked in our own panel never reached the page when the site’s file field lived inside a frame — the answer went to the main document, where no such field exists, and vanished in silence. A file name in Latin letters was read aloud by a GERMAN voice on a Russian interface, because the panel took the first reading language that shared the alphabet, and German happened to be first in the list; a name written in twenty-six Latin letters is evidence of no language at all, so it is read in the neutral one now. Hovering the address suggestions did nothing whatsoever — no highlight, no voice; a hover rule in the stylesheet would have given the eye half of it and the ear none, so hovering now moves the same cursor the arrow keys move. And the address bar showed the address of an embedded frame instead of the site: the «navigated within the page» event arrives from ANY document of the tab, and the handler never looked at which one, so a companion frame calling history.pushState rewrote the bar and wrote its address into your history. For someone who cannot see, the address bar is the only place the name of the site is written.
How much the browser explains is now yours to choose — and three things it used to answer with silence
The browser now asks a second question on the first run: how much you want to be told. Three answers, and each one says a real phrase in its own manner instead of describing itself — you hear the browser you are about to get before you agree to it. Detailed says roughly three times as much: it names the key that undoes what just happened and tells you where you have landed, which is what a child or a first-day user needs. Brief says the fact and stops. The middle one is the browser as it was, word for word, and a level only changes phrases we wrote a second form for — so nothing can be lost by trying one. It is changeable at any time in the settings. Building it turned up something worse than the feature was: the page reader had its own translation door and consulted the dictionary directly, so the levels worked in the menus and did nothing on web pages — that is, everywhere a blind person actually spends their time. Three other silences went with it. Pressing back or forward at the ends of a tab’s history did nothing and said nothing, in all six places that ask for it; someone who can see the greyed-out button never presses it, and without sight the only available conclusion is that the browser is broken. A new key answers “where am I now” with the page, the section and what is under the reading cursor — the repeat key is deliberately verbatim and never answered that. And a refusal to send a page to the cloud, recorded once, was being spoken again on every new page, across the page’s own announcement; on a first visit a dialog about the cloud could even open by itself before anything was pressed. Schools and students now have a free key for ten years, with the paid features on and their own monthly allowance; a parent who buys Care has it ADDED to the school key rather than replacing it — the gift is not something we take back in exchange for money.
One page in the studio kept its own copy of the language, and nothing else could reach it
Switching language in the studio’s top bar changed every page but this one. Shift held the language in its own state, read once when the page opened, and was subscribed to neither the switch nor the storage behind it — so a reader who chose Ukrainian went on reading English, with the language control cheerfully showing UK. The page carries seven hand-written translations, and none of them could be reached after the first paint. Looking for why, it turned out the language was not the only thing this page did differently. Four protections that every other landing has had for weeks were missing here, and each one was visible: the cloak that hides the page until it is ready hid the studio’s own sidebar and top bar too, although they arrive already drawn — which is why a reload of this page, and only this page, made the whole frame blink out and back; the opt-in that lets one page fade into the next was absent, so walking into Shift from the rail was a hard white-then-dark reload; a single line of styling was missing from the head, so the first frame was painted with the browser’s default margin and the whole page jerked eight pixels on every load; and a render that failed left a white screen where every other product shows a branded page. All four are in now, copied from the pages that had them. Two more were quieter. This was the only page in the whole site declaring itself Russian while rendering English — a link pasted into a chat previewed in one language and opened in another, and a screen reader picked Russian phonetics to read English text. And it was the last product page from which the privacy policy, the terms and the refund page could not be reached at all, while the visitor counter ran on it like everywhere else. The seven translations were not touched: not a word rewritten, not a word machine-made. What changed is where the page looks to find out which of them to show. And since the translations exist, they now have addresses of their own — six crawlable pages, one per language, with head copy written from the page rather than translated from the Russian.
A blind tester downloaded an Arabic voice, opened an Arabic page, and heard nothing at all
He did everything right. The catalogue showed the voice, the download finished, the page was Arabic — and the browser was silent. What he could not know is that the silence came from a guard put there on purpose a week earlier, for a good reason. Beyond the alphabets — Latin, Cyrillic, Greek — a synthesiser handed text it cannot read does not speak with an accent, it reads out the NAMES of the characters: an English voice on a Japanese sentence produces ten seconds of «Japanese letter, Japanese letter». So a phrase in a script the voice does not know is refused and handed to the person’s own screen reader instead, which is the right answer. The flaw was narrower and worse than a wrong rule. The guard asked whether ONE voice — the one chosen in settings — could read the phrase, while the speech engine had for a week been able to read a single sentence with SEVERAL voices, switching per fragment by the page’s own lang markup. The rule for «which voice reads this fragment» lived inside the function that splits a sentence up; the guard stood above it and knew its own, narrower version. Two places holding one rule differently — that was the whole defect. So the Arabic fragment was thrown away before anybody asked whether an Arabic voice existed, and the installed one was never consulted. A second, quieter hole sat underneath: the engine records «no voice for this language» inside the very function that was never reached, so he did not even get the sentence explaining what was missing. Silence, and no reason for it. Both are closed: the guard now judges each fragment by the voice that will actually read it, and a refusal records the missing language either way. The guard was not removed, it was taught — Japanese without a Japanese voice is still refused and still goes to the reader. What makes this one worth writing down is the instrument. There WAS a stand for Arabic reading, and it was green the entire time the product was mute, because it called the sentence-splitter directly and walked straight past the guard sitting above it. It now asks the same question the product asks, by the same name; proved by breaking the fix on purpose, which turns exactly those checks red and leaves the rest green. Three more things he asked for, all of them the same shape — the product was right and the person could not tell. Settings had their own menu entry and their own shortcut, and we had written to him twice to say so; the entry was called «Appearance settings» and sat under Accessibility, so somebody walking the menu bar by ear, listening for the word «Settings», never heard it. It is called Settings now, in all twenty-five languages — and the rename exposed a gap in our own translation pipeline, which fills in MISSING keys and leaves changed English alone while stamping everything as up to date, so twenty-two languages would have kept the old wording with every check green. It also stopped being a toggle: an item named Settings that closes settings on the second press is indistinguishable, without a screen, from one that did not work. Several menu items led into settings and all of them landed at the top of a page with over a hundred stops; jumping to a named section is now how every one of them arrives, which is what «Sign-in keys» in the account card should always have done. And downloading a voice from the settings list reported nothing: the percentages were spoken aloud at the quarters and sent to two other screens, but not to the list itself — so sixty megabytes went by with no way to check whether anything was happening. A spoken quarter cannot be re-read; text can. The figure now sits beside the button as plain text, in megabytes when the server declines to say the total rather than inventing a fraction, and the button tells a screen reader what it is doing and to which voice.
A blind person hit the certificate screen and heard only that the page had failed — not that the way past it was one Tab away
A site with a broken or self-signed certificate does not open, and it should not: that is the browser protecting somebody. But it is also the single most common way a page refuses in the countries where our users live — a municipal site, a clinic booking form, a small shop whose certificate expired last week. Our own screen appears instead, and it has two buttons on it: try again, and continue anyway with a warning about what that means. Sighted people see both. A blind person heard one sentence — «the page did not open, here is why» — and that was the end of it. The second button existed, was reachable by keyboard, was correctly named for a screen reader, and was never mentioned, so the only way to discover it was to Tab around a screen you have just been told is a dead end. Most people do not; they conclude the site is unusable and leave. The announcement now names the escape hatch by the same label the button carries, so what you hear and what you land on are the same words. What makes this one worth writing down is how it was found and how it is kept. The acceptance rig had four checks pointed at this screen, all four green, all four measuring the OLD behaviour — a neighbouring session had deliberately changed the policy weeks ago and the checks had quietly adapted to the change rather than catching it. Green there meant nothing. They were rewritten to five, and the fifth was proved by breaking the fix on purpose: with the announcement disabled the run goes 547 of 548 and points at exactly that line, and green again when it is restored. A check that has never been seen to fail is not a check. Three other instruments turned out not to have been running at all — the context menu, the tab strip and the mouse ring — each failing in under a second with a message about a missing export, which is what Electron says when the editor’s own environment variable makes it start as plain Node instead. They had been failing that way silently, so this release is the first in some time whose gate is what it claims to be: 117 instruments, and the three that were pretending are now among them.
The page had been saying twenty-one languages and thirty-two voices out loud, in every language, for weeks
The Arabic page opened with an ENGLISH voice, because the track had never been recorded — the code politely falls back to English when a language has none, which is the correct behaviour and the reason nobody noticed. It is recorded now, and it is the only language on the page read by a native rather than by the English narrator who covers everything without one: the other languages are heard by a sighted sceptic to whom an accent is no obstacle, while the Arabic page is heard by a blind speaker for whom the track IS the product. Modern Standard, not a dialect — one page for the whole Arabic-speaking world. Then the recogniser we used to check it read the last sentence back, and the last sentence said twenty-one languages and thirty-two voices. Counted against the engine’s own catalogue rather than against memory: forty-six entries, of which four are a second speaker inside the same package — still forty-six things a person picks from — across twenty-two languages. So the number had been wrong on the page for weeks, and wrong in a place nobody reads: it is the first thing a blind visitor hears, forty seconds in. Two places in each of twenty-five dictionaries, and because the numbers are written as words this was grammar rather than digits — Polish changes the noun’s case, Arabic the gender of the numeral against «لغة» and «صوت», Hungarian turns huszonegy into huszonkét before a noun. Three more places turned up on the way, none of them where anybody was looking. The Japanese track carried a THIRD number of its own — twenty-seven voices, in digits, next to a bullet on the same screen that said thirty-two: a Japanese reader saw one figure and heard another, and both were false. The same paragraph sat on the documentation page. And in the internal voice document, which is most likely where the page copied them from in the first place. All twenty-five tracks were re-recorded, and four of them — English, Russian, Japanese, Arabic — were run back through speech recognition to confirm the spoken number matches the written one. The Japanese needed the larger model to settle: the fast one heard «にょんで16» where the track says forty-six, which is the instrument being wrong rather than the recording. One quiet improvement underneath all of it: these twenty-five tracks had never been made by any script — they were typed into a web interface by hand, which is exactly why a new language of the page stayed mute. A new language is now one command, and the text comes from the same dictionary key as the transcript printed under the player, so what a deaf visitor reads and what a blind visitor hears cannot drift apart.
Legato is in the Microsoft Store, which is the first way to install it on Windows without being told it might be a virus
It was submitted for certification on the 27th and passed on the 28th, including the part nobody could predict: the permission it needs to run a full browser engine, its own speech and a conversation with the accessibility services is approved by a person at Microsoft rather than by a machine, and that person said yes. The page is live, the search finds it, and it is free in all 240 markets. What this changes is narrower and more important than «we are in a store». Our own Windows installer is unsigned — the certificate has been paid for since the 9th of August and is stuck behind a postcard sent by ordinary mail from Houston to Zaporizhzhia — so SmartScreen meets the file with a window in which the only visible button says «Don’t run». The button that lets you continue appears only after you open «More info», and somebody installing by ear has no way of knowing that. The Store copy is signed by Microsoft: no window, no unknown publisher, and updates arrive through the system. So the download block on the page now has four buttons rather than three, and the Store sits second, straight after Windows, because it is the second door into the same system and a person listening should hear the two of them together rather than after two Mac buttons. It is drawn as an outline rather than a fill: the main path is still the direct download, this is the quieter alternative. The arrow leaves a frame instead of pointing down, because nothing lands on your disk — Microsoft hands no .msix to a browser, ever; the install happens inside the Store app on Windows itself. That also means the link does nothing on a Mac, which is the store’s design and not our fault, and worth knowing before somebody reports it as one. Twenty-five dictionaries carry the two new lines, and in Arabic the arrow mirrors, since a sign that points somewhere has to point the way that writing runs. One honest gap: the copy in the Store is 0.3.67, one version behind the site, so it does not yet contain the two fixes Mehdi asked for. The update has to be packed on Windows and go through certification again.
The keyboard stopped being thrown out of the room every two seconds, and a running agent learned to say what it found
Fifteen reviewers went through Offer, Route and Deal, five lenses each, and the same fault turned up in all three products from three different angles. All three redraw themselves while an agent works — the board in Offer every 2.5 seconds, the trip in Route every second, the console in Route after every click. Writing markup that way destroys the nodes, and the browser has nowhere to put the keyboard focus, so it drops to the top of the document. In plain terms: while the agent was working, the page could not be walked with a keyboard at all. Every tick, the person started again from the top. Nobody had reported it, because it is invisible to anyone using a mouse and unremarkable to anyone who has given up. What comes back now is not only the focus but the caret, the selection, and any block the person had opened — the last of those is why the agent’s raw log in Route used to snap shut once a second, which made it unreadable exactly while it was interesting. The second half is worse and simpler. A run was mute. Not quiet — mute: the number of finds was never announced, in any of the three. Meanwhile the one live region on Offer’s screen was spending itself on a carousel of explanatory facts, one every fourteen seconds, and Route’s was reading out the names of the animation steps every 1.8 seconds. The noise was on the empty thing and the silence was on the real one. A blind person could start a search in Deal, sit through twenty minutes, and hear nothing at all — not the start, not the finding of twelve companies, not the end. The end was announced only when the run FAILED. Now the count speaks, and only when it changes; the agent’s own question in Route interrupts rather than waits, because it stops the whole flow until it is answered; and a finished run says so, including when it found nothing, since silence there reads as «still thinking». Three more, each found by measuring rather than reading. A failed run in Offer was reported as «we looked and found nothing», so somebody whose Claude window had run out was told the agent had walked the boards and advised to widen their search — advice that could not possibly help. The Stop button carried a careful guard against the engine dying, written a month ago, attached to markup that does not exist; the real button had none. And Route would move a trip to «ready to pay» when the agent came back with prose instead of an answer — a report with nothing filled in, under a button offering to mark it paid. The studio’s own surfaces were rebuilt in the same pass: the rail was the last thing painting itself from its own token, which is why «make the content darker than the rail» never showed — measured, the two were 0.2 apart in lightness while the headers sat 4.3 above both. One plane for the rail and every header, one for the field under them, and a single soft light from the centre that follows the chosen tint. Not the tint of whichever app is open: that was the reason one screen glowed in two different colours. Where the light belongs turned out to be a measurable question rather than a matter of taste: a soft radial reads as light only on a plane large enough to spread it, and on a strip fifty pixels tall the whole falloff lands inside those fifty pixels and becomes a bright band across the screen instead. So the two tall planes keep it and every strip is flat. The last one to hold out was Route, whose header was not the shared component at all but the app’s own bar, painting itself with two hardcoded colours — a translucent slate with a blur, which made sense while it floated over a coloured canvas, and a dark teal that outranked the shared plane. Measured side by side it sat visibly darker than the rail beside it. Both now apply only on the product’s own page, where they are its identity; inside the studio the bar takes the shared plane and can no longer drift away from its neighbours. One more, and it is the kind that only shows up for the people who need the setting: at the largest interface size the whole page grew a scrollbar and a dark band appeared above the footer. Both were the same arithmetic. The size control works by zooming the page body, so anything measured in rendered pixels and then fed back into the layout gets multiplied twice. The footer was measuring itself that way — 52 layout pixels tall, reported as 67, reserving 88 — so the rail and the field stopped twenty pixels short of the footer and the ground showed through between them, and the rail, short of exactly those pixels, started scrolling. The page itself had the same fault one level up: its body is told to be one screen tall, and the zoom then made it a third taller than the window, which is where the scrollbar came from — not from the rail or the content, which is why nothing inside them could remove it. The zoom step is now written down once and divided back out, so the two numbers cannot drift apart. Measured after: zero overflow at all three sizes. And one button on the Ops page was wearing the wrong pair of colours: dark lettering on a mid-blue fill in the dark theme, which is hard to read and looks like a mistake because it is one. The set keeps two separate accent tones on purpose — one for icons, borders and links, which lightens in the dark theme so those stay visible, and one for button fills, which stays deep in both themes and carries white lettering. This button was reaching for the first pair, so it inherited the ink that belongs with a light accent and put it on a fill that had gone light underneath it. Four other products already live by the button pair; this one had been missed. It now measures 6.69:1 in both themes. The first attempt at that fix nailed the lettering to white and broke the same button on the public landing, where the studio’s tint layer does not exist and the fallback lands on the environment’s own bright orange — white on it measures 2.54:1. The contrast gate caught it before it shipped, which is the entire reason that gate stands between the build and the domain. The lettering now travels with whichever fill it lands on. Two more things about moving between screens. Pressing the rail row for the tool you are ALREADY in reloaded the whole page — since each product became its own document, a rail row is a real navigation, and for the tool already open that meant tearing down and rebuilding the entire frame to arrive back where you started, losing your scroll and the tool’s state on the way. It now does nothing, which is what it looked like it should do. And every page carries a small block of colour that paints before its stylesheet arrives, so the screen is never white for a beat; those colours had drifted away from what the studio actually paints. Measured one reload at a time: the light skin showed a warm cream and then arrived at a cool grey, the dark one showed a lighter slate and settled darker. That is the two-colour flicker. All eighteen pages now hand over to the exact colour they land on — inside the studio only; a product’s own page keeps its own palette, which is part of its name. And the page has a third way of healing itself now. It already noticed when one of its own files fails to load, and when the tab is simply holding last week’s build. What neither could see: a file that arrives with a perfectly good 200 out of the browser’s own disk cache and turns out not to be a stylesheet at all — the residue of an old caching fault where a missing asset was answered with a page. No error fires, the build number matches, and the person is left looking at bare markup: a list of links and a system media player where the tool should be. That is what one of us hit on the live site while the server was serving 1342 rules and a clean browser opened the page whole. The check is direct — a stylesheet that produced no rules did not apply — and one refresh puts it right.
The home page became a drum, and the studio stopped painting itself five different greys
The home page used to be a shelf of tiles. It is a conversation now: a line says what a person needs — «I need to find a job», «I need customers» — and the line under it answers with the name of the tool that does it, which is also the line you press. Seventeen of them turn on a wheel, one detent at a time, with a click; the sound has a switch and the whole shelf is also there as a plain list for anyone who would rather not turn anything. What the rebuild found underneath was worth more than the page itself. Measured across thirteen screens, the rail sat at one shade and the panels inside the apps at five others — 0.037, 0.029, 0.025, 0.021, 0.017 — and nineteen different border tokens were in use. Nobody had chosen any of that against anything else: each app had reasonably invented its own, and the studio was the first place they met on one screen. There are two planes now, one line colour and one speed, all of them read from six values in one block, so changing a number moves the whole studio — both themes, both styles, twenty-five tints, every app. The header strip above each tool became one component rather than eight, opaque and sticky, and the corner of a card went back to the style switch: 4px in classic, 14 in modern. Three faults were only findable by measuring rather than by reading. A button whose label stayed dark on a coloured fill through three attempts to fix it, because the button has no colour of its own at all — it inherits one, and inheritance cannot be beaten by a selector. Pages that appeared to slide into place on load, which was never an animation: the class that says «we are inside the studio» was added after the first paint, so the page drew itself as a standalone landing and then snapped. And a divider in one product, meant to be a hairline, arriving 92 pixels tall. The gate on the way out caught a fourth, which the same tidying had just created. Once the legal and about pages started reading their colour from the shared set, they took the accent meant for FILLING a button and used it for WORDS — and on the dark ground that is a step too deep: links at 3.74 against the 4.5 the standard asks for, section headings at 4.45, inline code the same. Four hundred and sixty-seven pieces of text across thirteen pages, and none of it visible to anyone reading the stylesheet, because the rule said «accent» and the accent was correct — for the other job. The set has carried a separate tone for small text for weeks; these pages simply did not know about it. Nothing shipped until all four hundred and eight page-renders came back clean. The keyboard gate then stopped it once more, on the drum itself. Seventeen of the forty-nine places focus can land on the home page had no ring around them — they changed colour and grew an underline, which tells you nothing if you did not see the state before. That list is invisible until it takes focus, so the ring is the only thing that says WHICH of the seventeen you are standing on; it was switched off in our own stylesheet. It is back, on the list and on the answer, and the mouse keeps the quiet underline it had.
The Legato page speaks Arabic too — and the photograph found what the code hid
The browser learned Arabic this morning; the page it is downloaded from was still written in twenty-four languages, so somebody whose browser spoke to him in his own language arrived at a page that did not. Twenty-five now, and the first one that reads right to left. The writing direction is set beside the language, in one line: without it an Arabic page lays out left to right — lines pushed against the wrong edge, and a screen reader walking the markup rather than what is visible, naming things in an order nobody sees. What makes this worth writing down is the two faults that the code could not show. The language switcher came out EMPTY. The name and badge tables are declared as complete records over the language type, and the comment beside them promises that a forgotten language breaks the build rather than the page — it did not break: the build strips types without checking them, so the guarantee that comment relies on does not exist. In the photograph it was a blank pill where «the Arabic» should be. And three arrow glyphs pointed backwards. The layout swaps the sides of a row, but not the sign inside it, and in right-to-left «onward» is leftward — so each of them pointed at what had already been read. Ticks and crosses have no side and were left alone. Checked by picture rather than by argument: twenty-seven screens in a row, nothing over the edge. The dictionary is machine-made and NOBODY HAS PROOFREAD IT — unlike the eight second-wave languages, which were read by a human. That is written into the file itself. The judge is the same blind Arabic speaker who asked for the language in the first place, and until he says otherwise, Arabic is not announced anywhere as finished.
Legato 0.3.68 — the browser now closes itself so the installer can work, and the interface learned to run right to left
Mehdi, a blind tester, updated on Windows and wrote down exactly where it stopped being simple: the installer opens, you press Next, and it tells you to close the browser first. For someone sighted that is one extra click. For someone listening it is a dead end in the middle of an update — «now what do I do, and how do I get back to the installer after closing the program?«. The browser closes itself now. It says out loud that it is closing so the installer can work, waits for the sentence to finish, and goes; the last page of the installer has «Open Qiksy Legato» on it, which is where you come back from. Only on Windows: on a Mac you copy the app out of the disk image by hand, and the browser is still needed at that moment. He also could not find the Arabic voice in the settings by ear, and the reason turned out to be duller than an encoding bug — the voice was named «كريم», in a script that nobody who can reach that list is set up to read. It is called Kareem now, in Latin letters, and the native spelling comes back the day there is an Arabic interface to put it in. The interface itself learned right-to-left, and the honest half of that story is that three of the faults it uncovered were never about Arabic. The back and forward arrows did not mirror: the buttons swapped places with the layout while the glyph inside kept pointing left, so the first button pointed the opposite way from what its own label said. The buttons inside the new-tab search field were pinned to the right edge while the space reserved for them travelled with the text, so the placeholder ran into the icons — and that one was found by photographing the screen, not by reading the code, because the measurements said everything was fine. And the «skip to content» link, hidden off-screen the classic way with left: -9999px, stretched the toolbar by nine thousand pixels of horizontal scroll, because in right-to-left «off-screen» becomes «into the document». Seventeen asymmetric paddings moved to logical axes at the same time; not a pixel changed in English, which was checked rather than assumed. Every screen and every pop-up was then opened one at a time in both directions and measured against itself in English — thirty-three pages, ninety-one states — and the mirrored comparison came back clean. There is an Arabic dictionary in this build, all 3203 keys of it, and it is machine-made: no native speaker has read a word of it yet. It is marked as unreviewed in the repository for that reason, and it is not being announced as a finished language until someone who reads Arabic says it is one. One more thing, and it is the least comfortable. This release was stopped at the gates by a stand that had been failing silently — the walk through the first five minutes after installation, the ones in which a blind person decides whether to keep the browser at all. It needed a WebSocket that this version of Node keeps behind a flag, and it fell over before testing anything, while the gate above it went on reporting success. Nobody knows how long it had been dead. It runs now, and it passes.
A page froze for seven seconds and would not take a keystroke — and it was us, not the network
The owner opened Google Translate: five seconds before anything, and the input box refused to take a single letter. The obvious suspects were all wrong. It was not the network — measured side by side, a plain engine and ours both reach readiness in about 700 ms. It was not the cache either, which is why reloading never helped: a cache saves network, and what we were spending was the page’s own main thread. The profiler named the culprit outright: 94.5 % of our scan sat inside one check. To describe where a finding lives we build a CSS path from the node upwards, and from the eighth level on we asked the WHOLE document, at every single level, “does this path match exactly one node?” — a long selector, a document of sixteen thousand nodes, hundreds of findings. The question turned out to be unnecessary: a path carried all the way to the root, with the child’s index at every level, is unique BY CONSTRUCTION. We now ask only where the path had to be cut short. Scan 6954 → 352 ms; the contrast measurement 7216 → 289 ms. The repairs themselves are untouched, and so is the shared cache — its key is computed from the node’s markup, never from the path, so not one hash moved. The guard that protects this was built wrong twice, and that is worth writing down. The first version measured milliseconds on a synthetic page, and with the fault deliberately put BACK it stayed green: the trouble does not live in depth, it lives in AMBIGUITY — the old code stopped as soon as the path became unique, and on generated markup it becomes unique immediately. The page is now forty identical branches, so a path tail matches forty nodes rather than one, and the measure is no longer time but the number of document-wide queries per finding — the disease itself rather than its shadow, and independent of how fast the machine is. Starved, it reports 9.0 queries per finding against 0.0 healthy. Also in these two releases: a Help menu, because a totally blind tester wrote that he had no way to find out which version he was running, and “you have the latest version” is a black box to someone who cannot read his own version number — he cannot tell a successful background update from a fetcher that is quietly failing. The check now says the number in the same breath as the verdict, and About / Guided Tour / Check for Updates live in the menu bar, where help is looked for without needing to know a shortcut first. One more, found by the keyboard gate on the way out: on the download page the very first thing a keyboard user meets — “skip straight to the download” — pointed at an anchor that does not exist on that page, so it did nothing at all, and silently. That is the worst shape a fault can take: you press, nothing happens, and you cannot tell whether the page is broken or you are. The heading level under it jumped from one to three as well, which breaks the outline a screen reader walks by.
Legato 0.3.65 — the file that never reached the site, and four instruments that were measuring the machine
Uploading a file to somebody else’s site had been failing silently, and the reason is worth stating plainly: almost every modern uploader creates an <input type="file"> on the fly, clicks it, and removes it from the document again, keeping only its own reference. Legato refused to deliver into a field that was no longer in the document — so you chose the file, pressed the button, and nothing happened, with no sound and no message. Listeners live on the element rather than on the document, so it delivers now, and the stand has that exact case: it goes red without the fix. The file panel also opens where you took a file last time instead of always in your home folder, and it scrolls in one place — the whole window used to scroll, carrying the “where am I” line off the top edge, which for someone listening is the one line that answers the question the panel exists for. The right-click menu had been cutting words off on Windows: the card measures itself to ask for a window its own size, and it was doing that before the interface font had arrived, so it was measured in the fallback face. On a Mac the fallback is near enough in width to hide it; on Windows it is Segoe UI, and “Open in another browser” came out as “Open in another brow”. It measures a second time once the font is ready. The focus ring Legato draws on sites that have none now appears from the keyboard and not from the mouse. :focus-visible was not enough on its own — it answers “does this element need a visible focus mark”, and for a text field the engine answers yes even for a plain click, so clicking into a search box put a heavy ring around it for a sighted user who did not need one. The tab menu gained “Add to bookmarks”, and the selected section in the side column is marked by a ring rather than a pale fill that measured 1.28:1 against the three that WCAG asks for. Voice catalogue: 46 voices. The uncomfortable half of this release is about our own instruments. Four of them were measuring the MACHINE rather than the product — each waited a fixed number of milliseconds for something whose length is not ours to choose. Under load the synthesis of a single chunk takes as long as a whole phrase used to, so the ear walked out of an area before the browser had finished naming it and then blamed the browser; the voices stand collected half of a seven-language phrase and reported it as truncated; the voice catalogue judged Turkish and Ukrainian with a listener that cannot hear them — the same voice on the same three sentences scored 13, 24, 61 and 83 percent errors in different runs, and 11 with the larger listener. And a timing-sensitive run was listed for isolation under a name the runner does not use, so for two months it ran in a crowd of fifteen and reddened from the company. One thing is still open and is written down rather than hidden: under extreme load the name of an area can fail to reach sound at all when you enter the toolbar. The phrase-joining that this release fixes is visible working in the trace; the cause is deeper, in the ordering inside the synthesiser, and it is the first item of the next release rather than a line quietly left out of this one.
Record a form flow once, replay it with one press — and six things that had been lying about their own work
Scenarios shipped: press Record, fill the form the way you normally would, press Stop and name it. Afterwards one press replays it — across the steps of a wizard, across pages, and across sites, because a flow is rarely one page and a sign-in hand-off or a payment page on somebody else’s domain is part of it. It waits for you at every page boundary, since a page that has just loaded is not a place to type unasked, and it stops at the first field the page no longer has — naming that field rather than reporting a number. Passwords and card numbers are recorded as fields and never as values, because a scenario is a file you can export and send. The bridge got the same version on npm the same day. The other half of the release is uglier and more useful. A menu built from anonymous divs — which is most hand-rolled ones — was read as an empty list, so the widget was reported as “did not respond” while sitting there perfectly openable; rows are recognised by shape now, not by class name. A read-only box that opens a list was dropped by the scanner as if it were a caption, so the field was skipped SILENTLY and the form still counted complete. “Filled 2 · skipped 2” now names the two, because a count you cannot act on, in front of a form you have to submit, is how a half-filled form gets taken for a finished one. Validate had been answering “everything here validates” about a form with two fields that validate nothing — it looked for a red line “near” the field and “near” could be the wrapper around the whole form, so one field’s genuine error vouched for its neighbours. The agent bridge’s fast pick was matching an option anywhere on the page, so with a suggest box left open elsewhere the value went to a field nobody had named. And a required asterisk drawn beside a control was being recorded as part of the value — found not by a test but by photographing the panel for this page. Each of those now has a stand of its own that goes red before the fix and green after.
A Spanish message in a Russian interface was being read aloud in Russian. Not any more
The open chat had no way of saying what language a message was in. A page declares one language for the whole document, so a screen reader took every message in that one — a line written in Spanish came out with Russian sounds, or was spelled letter by letter. This is exactly the fault our own browser exists to repair on other people’s sites, and it was sitting in our own room. Two fixes, because either one alone is half a fix. The language is now worked out when the message is SENT, where the text is whole and fresh, and stored with it: the reader gets a fact rather than a guess made from three words. For everything written before today there is no stored language and never will be, so it is worked out when the message is drawn. Both halves refuse to answer when they are not sure — a short «ok» or «thanks» gets no language at all, because a wrong language mark is worse than none: the reader then says a foreign word confidently and wrongly, and the person listening concludes the text is broken rather than the label. And the page about who we are, which had been reachable only from the footers of some pages, is now in the studio rail with a way to write to us next to it.
The row of counters above the chat feed is gone — what is left is one icon in the header
It arrived three releases ago as five buttons, was cut to one, and is now not a row at all. A whole band of height was being spent on a filter that matters on a long run — which is to say rarely — while the panel already has a header. So the count moved there, beside history and “new conversation”: a funnel with a number, and nothing else. A funnel rather than a flag, because the flag in this window already means “keep this as a finding” and a second flag beside it would read as one more finding. The tooltip says both what the number is and what pressing it will do, because there is no “show everything” button next to it any more — the way back is pressing the same icon again, and leaving that unsaid is exactly the trap the old “all” button existed to prevent. The filter takes both bad outcomes at once, since the number counts both: promising five and then showing three is worse than showing nothing. It appears only when there is something to filter to — no failed steps, no icon, however long the run. Worth writing down is why it did not work the first time: the dock builds a panel’s header exactly once and says so in its own source, “static by design: they fetch their data on press”. An icon whose existence depends on a number therefore never appeared at all, because the panel is born before the conversation. The node is permanent now and its number, state and visibility refresh from the feed’s own redraw — before the early return on an unchanged signature, since that signature guards the body of the feed while the count can change without the body changing. Two smaller things in the same pass. The pressed state of that icon used to add its border on press, which widened the button by two pixels and made its contents jump every time; the border is always there now, transparent until it is needed. And a step’s line was ending mid-word — “did not go th” — because all three of its parts were set not to shrink, so anything that did not fit simply left the panel with no sign it had been cut. The step’s name shrinks with an ellipsis now; the outcome is what the line is read for, so it stays readable to the end.
The row of counters above the chat feed is now one button — and only appears when something actually broke
It shipped two days ago with five buttons — all, errors, held, did not work, done — and four of them were dead weight. Exactly one does something nothing else can: jump to what broke in a run three hundred steps long. The rest are numbers nobody acts on, and the summary card at the end of a run already states them, in words, split into passed / did not pass / blocked / not checked, with an honest note of how many were actually measured rather than asserted. Two voices for one fact, where the second is poorer than the first, is not a summary — it is noise above the feed. The threshold was wrong as well: the bar appeared at eight steps, and eight steps is an ordinary short conversation, so it sat there in exchanges with nothing to filter. Two conditions now, both required — scrolling is genuinely hard, and there is somewhere to jump to. A clean run shows no bar at all, however long it ran; and since the “all” button is gone, pressing the remaining one again is the way back, so it says so rather than leaving you to discover it. Above the bar there was a dead 8-pixel band, because the feed carries a top margin to clear whatever sits above it while the counters are the first thing in that grid and stick to the top — measured before and after, 8 to 0, at rest and at every scroll position. And the “check this” button under an answer, which fills the composer with a ready sentence so it can be sent as it stands, was filling a box and then focusing a discarded one: the feed redraws at that moment, and the element found immediately afterwards is sometimes already gone. It fills and focuses on the next frame now. That one was caught by the acceptance run only in company — alone the check passed, after its neighbours it failed, which is the difference between “it works” and “it works after somebody else has been here”.
Six places in Jig had no background at all — including the bar that asks whether a page may use your camera
A CSS variable that does not exist is not an error. It is silence: the property is simply not applied, and nothing anywhere says so. Six rules referred to tokens this theme has never declared, and the results had been shipping for weeks. The permission bar — the thing that asks whether the page you are testing may use your camera or your location — had no background and hung transparent over the page it was asking about. The row of outcome counters above the chat feed had none either, so text scrolling underneath showed straight through the buttons, which reads as broken layout rather than a missing colour. The digit in the busy-project marker had no colour. The diff, the failure screenshot, the summary of edits and the action log had neither background nor rounded corners. There is now a check that reads every stylesheet and refuses any var() without a fallback that names a token nobody declared — exactly the kind of fault a screenshot cannot report, because on screen it looks like a decision somebody made. Two more in the same pass. The copy-the-address button had left the address field entirely: it is placed inside the field at the right edge, and a list of selectors added for something else — an invisible 24×24 target so small buttons can be hit by someone with a tremor — happened to name this one by its id, which outweighs two classes and silently replaced its positioning. It dropped into ordinary flow, to the left of the field and below its bottom edge, and had been there since 1.2. And the “check this” button under an answer, which exists to hand you a ready sentence instead of making you retype somebody else’s paragraph, was setting the draft while the feed’s redraw ignored it — so it focused an empty box. Last, a run you stop now leaves a trace saying you stopped it, instead of nothing at all: an hour later, which is when a conversation gets reopened, a run that broke off on its own was indistinguishable from one a person ended. Out loud it was worse — the window announced “run finished” after a stop, telling somebody who cannot check the screen that the work was done at the moment it was cut short.
Jig 1.3.3: a page can ask for the camera again, code changes arrive as changes, and the chat reads differently for a tester, a developer and an analyst
Jig used to answer no to every permission a page asked for — camera, microphone, location, notifications, USB. Meant as safety, it worked as a wall: a video call or a map could not be tested inside it at all, and from the outside that looks like a broken site rather than a decision somebody made. There are three levels now. Things a page asks about its own behaviour — full screen, writing to the clipboard, pointer lock — are granted at once, because a prompt for those only teaches people to click yes without reading. Everything else is asked, and until you answer the page simply waits, exactly as it waits for a Chrome prompt nobody has clicked; a minute of silence is a refusal. The answer is remembered per address, and the question is a bar at the bottom rather than a modal window, because a modal takes the focus — the one thing a screen-reader user is holding on to. Second: a file edit in the chat now unfolds into a real line-by-line diff with actual line numbers, read from the file on disk rather than counted from earlier cards, which drift the moment anything above them changes; where two lines are similar the part that changed is highlighted inside the line, because one renamed variable in a sixty-character line is not something the eye finds between two evenly red-and-green rows. The header used to say “+40 −40” for a change of two lines inside a forty-line block — it counts the change now. Open the file puts it in the editor at the changed line; Undo this change puts the old text back, but only if that exact text is still there, so a file that has moved on is not quietly returned to a state it was never in. Third: three people were asked what they needed from the chat feed and independently named the same noise, which is now gone — the random faces on every step (picked by hash, so two identical steps looked different and the eye could not group them), the “thinking…” line, the raw dump of call arguments, and the string of reading steps, now one folded line. Then their paths diverge and so does the feed: a tester gets a row of outcome counters above it, each one a filter, so a three-hundred-step run answers “is there anything to talk about” in two seconds, every step carrying the time, the duration and the address, a failed step turnable into a finding on the spot with a screenshot taken at the moment it failed; a developer gets edits unfolded without a click; an analyst gets the call detail folded away, a summary of what passed and what did not, and the action log moved to the bottom. Both Mac images are signed and notarised and the Intel one was run through the acceptance rig under Rosetta; the Windows installer is still unsigned while the certificate is in validation.
Jig 1.3.2: a blind tester can now work through the whole product — six things stood in the way
The ask was plain: make it possible to test the whole product without seeing it. So three people walked through Jig — somebody using a screen reader, somebody at 200% zoom, and somebody who cannot use a mouse — and everything they hit was fixed the same day. A project could not be opened from the keyboard AT ALL: the plate in the strip is a container with a click handler, the keyboard lands on the name field inside it, and that field listened to one key — F2, to rename. With a mouse the project opened; with a keyboard it never did, which for somebody who cannot see is not an inconvenience but a dead end. Closing a project happened in silence, because the sentence “project closed — reopen it from Settings” lived on the × button’s own handler: closed from the keyboard, from a command, by the model or from another window, a project simply stopped existing. And twenty-eight controls were under the 24px minimum — irrelevant to a blind tester, constant misses for somebody with a tremor; the isolated ones got an invisible 24×24 target around their centre while the composer’s rows deliberately did not, because two expanded areas side by side overlap and then the miss lands on the NEIGHBOURING button, which is worse than a small target. Then two real screen readers were pointed at it, and each found something every earlier check had called green. NVDA on Windows heard an opened tool announce itself as “document”: focus goes to the first control inside a panel, and an empty panel has none, so focus stayed on the document — a polite live region does not rescue that, because moving focus cancels it. NVDA also heard nothing where the list of keyboard shortcuts should be: it was spoken at the exact moment the dialog took focus, and the dialog announcement wins, so somebody asking for help got “Jig, region”. VoiceOver on macOS read out the entire first message of a conversation as that conversation’s name, cut off mid-word — invisible by definition, since on screen it is trimmed with an ellipsis and CSS never reaches a screen reader. All six are covered by acceptance that runs on every pass: a tab walk, the accessibility tree read straight from the browser, and the two readers themselves. Both Mac images are signed and notarised; the Windows installer is still unsigned while the certificate is in validation.
Our own JavaScript was answering Google with a redirect, so the pages we built for search were the ones being dropped
Search Console wrote to say that pages listed in our sitemap were not being indexed, reason: «page with redirect». The server was innocent — every one of those addresses answers a plain 200, with a canonical pointing at itself and a full set of hreflang siblings. The redirect was ours, in the browser. A language page has always been allowed to yield to geography: if you never picked a language yourself and the country the edge reports disagrees with the language in the address, we moved you to your own country’s version. That existed for a real reason — someone in Ukraine was sent a link carrying /ru/ and got the Russian landing, a language chosen for somebody else. What the code claimed, in a comment, was that crawlers never see this because they read the prerendered HTML. They do see it. Googlebot runs JavaScript and crawls from the United States, so every /uk/, /ru/, /de/, /es/ and /pt/ page politely redirected it to English — and fourteen of the exact pages that exist FOR search quietly left the index. Nothing navigates by itself now. The page stays where you opened it and makes an offer instead: one line at the bottom saying this page exists in your language, a button to it, and «not now». That is also what Google’s own guidance says to do rather than redirect by IP. The offer speaks the language it is offering, and carries that language on the element, because a screen reader otherwise pronounces Ukrainian words with English phonetics — help that arrives as noise. Refusing it is remembered for the visit, not forever. Finding that turned up something bigger that nobody had reported: thirty-four live, prerendered pages were missing from the sitemap altogether — every Spanish, Portuguese, German and Polish version of eight landings, and the whole of the accessibility-audit section. The pages are generated from a config; the sitemap was kept by hand; so every language added since July simply never arrived in it. The sitemap even carried a comment promising that our build fails when a language route is missing from it. That check had never existed. It exists now, and it is the reason this entry can promise it: the build walks the generated routes against the sitemap and stops if one of them is unlisted.
We were comparing a bridge against a script. Now it is bridge against bridge — and the numbers changed sides
Yesterday this page stopped claiming QA Copilot was faster than Playwright, because a fresh measurement said otherwise. Today the comparison itself turned out to be the wrong one, and the owner is the person who spotted it: we were racing our BRIDGE against a pre-written Playwright SCRIPT. A script is code inside your own test process — no agent, no protocol, no round trip — so of course it wins; it fills the same ninety-four fields in about 0.4s. That is not the thing anybody chooses between. What an agent actually holds is an MCP server, so the stand now runs a real @playwright/mcp on the other side, attached over CDP to the SAME browser and the SAME tab our bridge is working in — which is the generous setup for it, since left alone it launches a fresh blank browser first. Driving the form the way an agent does, one call per field, it takes about 3.0s and ninety-five calls; our one call takes about 1.4s. Median of three runs, and the video on the page is those two runs, with the call counters counting for real. One thing is stated rather than hidden: Playwright MCP also has a batch verb, browser_fill_form, and with it the same form goes in about 0.7s in two calls — but the agent has to build that list of ninety-four fields and their types itself, while ours takes a plain label-to-value dictionary and works the rest out. Hiding that would have lasted exactly as long as the first reader who opened their documentation. The stand is in the repository and runs with one command, both modes.
Legato 0.3.60: postcards you can actually send — and the picture arrives with its own words
A postcard in Legato is made to be heard rather than looked at. Pick a mood, write a line or two, press one button, and the picture comes with it — described in whole sentences, so the person who sends it and the person who receives it end up with the same postcard. The file is plain text with nothing executable in it, it carries its own language, and it is read in that language whatever the receiver has their interface set to: a Russian card under an English interface used to be spelled out letter by letter, and that is gone. The path to the main button is five keystrokes; a council of five blind testers measured forty-seven to reach the field you write in. And the picture can be built a layer at a time — background, who is on it, a magnet across the top — with each layer naming itself as it lands, and one key to hear the whole thing. Behind that, three defects that were only visible from a real screen reader. On Windows every postcard carried the PREVIOUS picture, and the very first one was a plain white sheet: the first frame after a redraw request delivers the old one there, and the code took the first frame it got. Found on an actual Windows machine, not argued from the code, and the person sending it heard “picture chosen” the whole time — the only instrument said everything was fine. Our own reader announced a CHOSEN radio button or checkbox as “not selected”, in our settings and on every site that builds its own — consent boxes, checkouts — so a blind person could not tell whether they had ticked it. And a licence with no end date read as “0 days left, valid until 1 January 1970” while the screen said “for good”, and quietly rewrote itself at every launch. The file picker is ours rather than the system one, for the plain reason that the system window is the one place our reader cannot help: it now keeps the main button reachable instead of dropping it out of the tab ring, and it says where you are and how many items are there — a sentence the reader itself had been cancelling one millisecond later. Both Mac images are signed and notarised; the Windows installer is still unsigned while the certificate goes through identity checks, and the download page says so and publishes the checksum. There is no in-app update yet, so this one is a download.
The speed claim on the QA Copilot page was wrong, so it was measured and rewritten — one call, not ninety-four
The page used to claim QA Copilot was faster than Playwright, over a video recorded in July. Both halves of that had gone stale, so it was measured again from scratch — and the claim did not survive. The stand is in the repository: one form, ninety-four fields, thirty-nine of them plain text and the rest selects, dates, numbers, checkboxes, textareas, URLs, emails and phone numbers; the page times ITSELF, from the first keystroke to the submit, so neither driver is trusted to report its own score. It is filled twice on two identical clean copies — on the left Playwright over the Chrome DevTools Protocol from a script, on the right our own bridge — and the video on the page is those two runs side by side, unedited, neither slowed nor sped up. The honest result is that Playwright fills this form in about 0.4s to our 1.4s, and on plain native inputs it will stay ahead; it runs inside your test process, and we go out to a browser and back. So the section now says that in as many words, in seven languages, instead of the sentence it replaced. What actually differs is the count: ours is ONE call — one round trip for the agent, one thing to get right, and it stays at one whether the form has ten fields or two hundred — against ninety-four, each of which an agent has to decide on, behind a script somebody wrote for THIS form and rewrites when it changes. Qiksy had never seen this form; it read the page, matched the labels and filled it. Measuring honestly also found a real defect, which is the usual reward: the fill was waiting for a dropdown list to settle after every single field, including the ninety-odd that have no list to open. Ninety-four fields went from 8.36s to 1.36s, and the cap is now paid only by controls that can actually open something — the same reasoning in both places that decide it, the bridge and the extension, because two answers to one question is how a fix half-lands. The old figures are gone from all seven dictionaries rather than from the English one.
Jig 1.3.1: hand a task to the project it actually belongs to, instead of retyping it
A tester keeps several flows open at once, and the mistake is an ordinary one: you start typing a task in this project and realise halfway through that it belongs to the other one, the one pointed at a different folder. Until now the only way out was to erase it and type it again, from memory, in the right window. Right-click the send button, pick the project, and it goes. Three decisions inside that, each against the obvious one: the task joins the QUEUE of the other project rather than starting by force — work may be running there, and “hand over” must not mean “cut in line”; you STAY where you are, because you are handing it over precisely so you do not have to abandon your own flow, and what went and where is said out loud by project name; and it lands in that project’s CURRENT conversation, since guessing which of its conversations a task belongs to is not something we can do for you. You can be wrong about the project after sending too — it is often easier to spot while looking at your own queue — so a queued task has a fourth button now that hands it over the same way. Alongside it, two things about keeping many flows at once. The ceiling on projects is ten instead of six: six was set in early August after a strip of seventeen ran off under the buttons on the right, and that reason is gone — plates shrink, the strip scrolls, and it now has pinning and an order of its own. Memory is still the real cost, since a project is a live browser with its own session, so a ceiling remains a ceiling and the eleventh is refused out loud rather than by a dead button. And closed projects, which have always come back whole with their tabs, context, checklist and findings, no longer live only in Settings: right-click the + in the strip and they are there — next to the thing that makes projects, in the same place where they were closed. Four acceptance acts cover this, and they judge the ceiling from both sides: that ten open, that the eleventh is refused, and that the sentence explaining the limit names the same number the code does.
Jig 1.3.0: the strip of projects finally says what is happening inside it
Jig has always known which project has an engine working in it. Until today that knowledge left the window in exactly one place — the little × asking “a task is still running here, close it anyway?” — and the strip itself said nothing. A project that is working now wears a dot in its own colour, with a digit from the second lane onward, which is the answer to “why did my next task queue up”. More important is the other half: a project that FINISHED while you were elsewhere keeps its marker until you go in. A dot that vanishes when the work ends tells somebody who stepped away for ten minutes nothing at all — it was there and then it wasn’t — so the ring stays, and it is cleared by arriving rather than by a timer, with a quiet low tone that is deliberately the least noticeable sound in the set. The project you are standing in never gets a marker; you are looking at it. Pinned projects have no close cross at all, which is the point: the window already knows how to ask before closing, and that is precisely the question people dismiss without reading — a guard you can click through is not a guard. Right-click unpins; pinned projects sit first. Both strips reorder by dragging, projects and tabs alike. The keyboard reaches them: Ctrl+Tab walks the tabs of the current project and wraps around, ⌘⌥→ and ⌘⌥← walk the projects in the order you SEE rather than the order they are stored in, and ⌘1…9 keeps meaning “tab” as it does in every browser — taking that away to spend it on projects would be a pure loss. Every move is spoken. A closed tab comes back on ⌘⇧T or from the right-click menu, which also learned to duplicate a tab into a clean cookie jar — “the same page, but I am nobody”, the most common check of the day — close the others, and close the ones to the right. Four acceptance acts were written for this and caught three defects on the way, none of them visible by eye: a pinned project stopped opening on click, “pinned” was being silently dropped by a whitelist of fields, and the first drag implementation was off by one when moving rightward. Both Mac images are signed and notarised; the Windows installer is still unsigned while the certificate is in validation.
Jig 1.2.9: on Windows the engine now arrives — and is recognised when it is already there
Jig fetches its engine once, by itself, so that nobody has to open a terminal. On Windows that had two failures stacked on top of each other, and the first was the cause of the second. It could not SEE the engine it had already installed: the check asks the binary for its version and waited four seconds, and a cold start of a 330 MB executable that Defender is opening to scan at that very moment does not fit in four seconds — so “did not answer in time” was being cached as the final word “there is no engine on this machine”, and Jig went off to download a second copy. It waits twenty seconds there now, and a negative answer that came from the timer is not remembered at all: it is about that second, not about that machine. Then it could not PUT the new copy in place, because renaming a finished download onto the final path fails while any process holds that file open — and the process holding it was Jig itself, having just asked the old engine for its version. The old copy is removed first now, both steps retry with a growing pause, and copying is the last resort; macOS passes on the first attempt and never saw any of this. The symptom people met was a red line on the very first screen saying the engine did not arrive, next to a perfectly good engine and a 337 MB half-file nobody could explain. Verified on a real Windows Server 2022 rather than argued from the code: a clean first run downloaded the engine, put it in place whole, left nothing behind, and the app reported the engine’s own version back. This release also carries the voice fix from 1.2.8, so voice input works again on both systems.
Jig 1.2.8: voice input works again — it had been broken in the two releases before this one
Two days ago Jig learned to answer in the language of its own interface rather than the language of the operating system underneath it. The change was right and the line that carried it was wrong: it asked the settings object for a value the way you would ask a function, so every voice recording and every question that went through that path died on the spot with a type error instead of being transcribed. It shipped in 1.2.6 and again in 1.2.7, which means anybody who pressed the microphone in either of those builds got nothing back — not a bad transcription, no transcription. Nobody reported it. It was caught by the last step of our own full working day on the bench, the one whose only job is to fail if the window threw any error at all during the run, and which is deliberately written so that it cannot be passed by doing nothing. That step is the reason this is a fix and not a report from a customer, and it is worth saying plainly: the feature had a test for what it produced and no test for whether it ran, and the difference between those two is a release. Both Mac images are signed with a Developer ID certificate and notarised by Apple; the Windows installer is still unsigned while the certificate is in validation, so SmartScreen will warn on first run.
Legato 0.3.59: the browser says the uncomfortable part out loud, on the way in
The previous version taught the browser to own up — to mark a name it worked out itself wherever a mistake costs money or cannot be undone, and to answer, on one keystroke, where any name under the reading cursor came from. What it did not do was tell anybody. A feature nobody was told about does not exist for a blind person: there is no glancing at it out of the corner of an eye, no toolbar to notice it in. So the first run now ends on a screen of its own, spoken, before the first real page: pages often name nothing, where a control has no name the browser works one out, that name is the browser’s and not the page’s, and it can be wrong. Three ways to check come with it — the marking that lands on roughly one control in three hundred, Alt+Cmd+N on anything at all, and a switch that extends the confession to every guess. There is deliberately no “I agree” checkbox: the button already means “I heard this”, and for somebody driving the machine with a single switch every extra press costs effort — the acknowledgement is made by saying it, not by collecting a click on a box. The shortcut is never baked into a translation, because the key has a different name on each platform and in each language; the screen exists in all twenty-four, Russian and Ukrainian written by hand. One quieter change with the same reasoning: the “first run completed” mark is now set by the LAST step rather than the second to last, so that closing the window between the Chrome import and this screen cannot make the browser skip the one thing it owes you about itself. Both Mac images are signed with a Developer ID certificate and notarised by Apple. The Windows installer is still unsigned — the certificate is bought and not yet issued — so SmartScreen will warn on first run.
Legato now tells you when the name it just spoke is its own invention
The reason this browser exists is that pages do not name things. A button with no label reaches a blind person as “button”, and Legato answers that by working a name out — from the page’s own markup, from a repair somebody else’s browser made earlier, or from AI — and handing it to the screen reader. Which means the browser is the author of a word somebody then acts on, and that word can be wrong. A guessed name on a button that deletes an account, transfers money or signs you out is not a cosmetic error. So the browser stopped letting its own guesses pass as the page’s. Where a mistake costs something — pay, buy, subscribe, transfer, withdraw, delete, erase, deactivate, close an account, submit, upload, sign out, recognised in the page’s own language as well as in English — it appends “name guessed by the browser” to what it speaks, before you press anything. That is on by default and lands on roughly one control in three hundred. Alt+Cmd+N, on Mac or Alt+Ctrl+N on Windows, asks the same question about anything at all: the browser says out loud whether that name is the page’s own, came from the shared memory of earlier repairs, was written by the AI, or was worked out on this computer — free, no licence, no account. And a switch in Settings extends the confession to every name the browser supplies, not only the costly ones. The first run ends on this now, in as many words and in the person’s own language, before the first real page rather than in a document nobody opens. It is the least comfortable thing we could put on a product page, and it is the honest one: a tool that fills silence for you owes you a way to tell its voice from the page’s.
Dark by default across the studio — and QA Copilot’s pictures are finally the product you get
The studio opens dark now. It has been the other way round since early August, and the reversal is a taste call rather than a discovery — but it is the sort of call that has to be made in one place or not at all: the default lives in a hook and in twenty separate boot scripts, and the moment those two disagree the page paints one mode and repaints in the other a frame later, which reads as a flicker nobody can explain. Anyone who has already chosen light keeps light; the choice always wins over the default. Alongside it, the QA Copilot page was re-shot from scratch. The old images were from July and showed a panel that no longer exists — different palette, different buttons, a different mark on the round button — and a product page whose screenshots do not match the download is a small lie that the visitor discovers ten seconds later. Seventeen states instead of eight, every one taken from the built extension against real data: the findings come out of an actual audit, the session timeline out of an actual walk through four pages with real thumbnails, the fill card out of an actual fill. Each is a PAIR, light and dark, and the page shows whichever matches the theme you are reading it in — a dark screenshot on a milk-white page reads as somebody else’s picture pasted into the layout. Two defects surfaced from the photographs themselves rather than from any test: the finding-group headers were printing dictionary keys, and a counter said “1 fields”. Both fixed, and the panel’s test run now looks for raw keys on its own — they contain no English, so the language check walked straight past them.
QA Copilot 1.12.0: the panel finishes the sentence, and it can find a Save button that is not in English
The previous release put the panel into seven languages, and it only got halfway: the titles were translated and the explanations under them were not, so a tester in São Paulo or Warsaw opened a panel in their own language that explained itself in English — which is worse than either extreme, because it looks finished. Every hover tip, every paragraph under a tool, the empty states, the toasts and the placeholders are in the dictionary now, 171 strings of them; sentences that carry a piece of code or a bold word are stored whole rather than cut at the tag, because German and Polish do not put the verb where English does and the word order belongs to the translator. Quieter and more consequential: four word lists decide what SENDS a form, what closes a modal, which dropdown rows are placeholders rather than options, and which field wants a date — and they knew English and Russian. On a German or a Spanish form the tool could not find the page’s own Save button, and it failed silently, because from the outside that looks like “this page has no form”. All four cover the seven shipping languages now, with an acceptance test in which every positive case is paired with a negative one: “Abbrechen” must not read as a submit, “Enviar” must not read as an exit, and a German shop called “Laden” must not be thrown out of a dropdown as a loading placeholder. Findings, session notes and the client report stay in English on purpose — they are pasted into a ticket that a developer in another country reads. The panel also got calmer: twenty-five muted accent colours instead of eight loud ones, the colour you choose now tints the whole sheet instead of four controls, the light theme is warm paper rather than blue-white, and its shadows are a hint rather than a hole. While measuring that, the most muted text on the light theme came in at 3.4:1 — below the 4.5 this very tool flags on other people’s pages. Fixed in both places it appeared.
Pick your own four notes on the Legato page — and read them out over the phone
In a room where several computers are working, a beep from the machine next to you sounds exactly like your own, and a blind person turns towards every one of them. Legato has always answered that by signing its own results with four notes of yours — first “this is me”, then “here is what happened” — but until now you could only meet the feature after installing the browser. The page has it too: type a name, hear the five ways it could sound, keep the one you recognise. A callsign is written in note letters, CEGA or DFAC, so it survives being said out loud — dictate it over the phone, put it in an email signature, read it off a forum post, and at the other end it sounds the same with nothing downloaded and no account. The page also plays the scene the feature exists for: three results in a row from three machines, one of them yours. Nothing plays on its own, every sound is spelled out in words, and the notes come from the browser itself rather than a copy — the four letters you pick here are the four you get after installing.
Jig 1.2.7: sign it in to a different Claude account from the one your editor uses
Claude Code keeps its login in a config folder, and Jig had never asked for one of its own — so it shared the folder with whatever else on the machine signs in the same way, usually the owner’s editor. One account for both, one allowance for both, and pressing “Change account” inside Jig quietly signed you out of your IDE. Sharing stays the default, because for a developer who is already signed in it is the version with no sign-in step and nothing to discover. What is new is the switch beside it: turn on “Sign Jig in separately” and the app moves into a folder of its own and signs in there, after which the two are deaf to each other in both directions. The switch never signs anything in or out by itself — it only chooses which folder is read — so you can turn it on, look, and turn it back off without losing either login.
Jig 1.2.6: it answers in the language of your interface, and the page now says what your computer will ask on the first launch
Somebody with Jig set to Russian asked the voice assistant a question in Russian and got an answer in English. It read like the model being wilful; it was not. The window was sending the language of the MACHINE — macOS was set to en_UA — instead of the language chosen inside Jig, and the prompt uses that as its fallback for questions too short to judge. A spoken question is almost always short, so the fallback fired most of the time. Four places in that same file already sent the right value; five had drifted, and now all of them agree. The same is enforced a second time in the main process, so a future caller cannot get it wrong quietly. Legato, which was checked for the same fault, never had it — it resolves the setting first and the system only as a fallback, and that is now written down beside the fix. Also new on the download page: a section that says what happens the first time you open the app, on both systems — which window Windows shows, which button is hidden behind “More info”, why it will say “Unknown publisher” while our certificate is still in identity validation, and the checksum of each published file with the one command that verifies it. The name is not what proves the file is ours right now; the number is.
Jig runs on Windows, and we checked it on a real one before saying so
There is now a Windows installer on the download page. What makes it worth saying is the checking rather than the building: the packed build was unzipped on a real Windows Server 2022 and made to run its own fourteen self-test modes there — the first-run wizard, navigation, the gates, consent, the outside door, scenarios, fields, recipes, cross-browser, layout, fit, validation, interruption — and the same fourteen were run on the Mac for comparison. Doing both is what made the answer trustworthy: eight modes failed on Windows at first, which looked damning until the Mac failed in exactly the same eight places. That is not a Windows defect, it is a missing test fixture on both — and one of the eight turned out to be a genuine mistake inside the test itself, where an address was mentioned instead of being substituted, so the check had been failing on its own typo on every platform for who knows how long. With the fixture up, thirteen of the fourteen pass identically on both systems. Honest limits, on the page as well as here: the installer is <b>not signed</b> — the certificate is still in identity validation — so Windows will show its blue "protected your PC" screen and you have to choose More info, then Run anyway. It installs into your own user profile and never asks for administrator rights. We would rather write that down than let your own computer contradict us a minute after you believed the page.
Jig 1.2.5: the administrator’s lock now holds, account logins stay on your machine, and the allowance is described the way it is counted
Three things an audit found by comparing what Jig says against what Jig does. A company that switches sharing off — with JIG_NO_SHARE or a policy file — sees both boxes greyed out and a line saying nothing is sent whatever the box shows; that was true of publishing a recipe and false of asking for one, so every form analysis still made a request, from intranet hosts included. It now passes the same two locks as publishing: consent, and the page being public. Second: when there is no Claude on the machine and the question goes through our cloud instead, it used to carry the logins of your saved roles and the addresses of your test stands. Passwords never travelled and still do not, but a login on an internal host is your client’s data, not ours — the cloud request now carries the role names alone, and the stripping sits in the sending itself so nothing added later can slip past it. Third, and this one was our own price list rather than the product: Pro was sold as “1,000 calls a month” while the engine counts seven separate, non-interchangeable pools. Nothing was ever short-changed — there are 1,440 across the seven — but somebody who used their three hundred failure explanations hit a wall at the 301st call of a thousand they had paid for, and the refusal did not say which pool had run out. The page now lists the pools, and the refusal names the one that emptied.
We ran the same audit a second time without the cap, and it found twice as much — including a hole in the morning’s fix
The first pass had been told to bring back its three best findings per area, which is a sensible way to keep a review readable and a terrible way to learn how many there are. Run again with no cap, and against a list of what had already been fixed, it returned twenty-eight candidates; nineteen more survived a sceptic whose job was to disprove them. The first thing it disproved was our own work: the tab-scope fix written that morning still let a call arrive with no tab named and land on whatever tab the person was LOOKING at, so attaching the app under test and then glancing at your mail pointed the agent at the mail — while asking for that same tab by number was refused. The gate was on the branch that names a tab and missing from the one beside it, which is the exact shape we had just spent the morning removing. Twelve more of the same kind: deleting an isolated session in MultiLogin never reloaded its tabs, so a tab the popup had just called deleted carried on talking to the site with the profile’s real cookies; "Recording paused" kept writing findings and network entries into the report that later goes to a client; a targetless keystroke bypassed the Pro and consent checks that every other verb passes; Legato’s shared name-cache reached the network on every public page with no way to switch it off, under a line promising "no internet, nothing leaves it"; Jig sent account logins and the addresses of internal test stands to our cloud with the question; the engine’s "npx qiksy stop" printed "Everything is off" while launchd restarted it seconds later; and a licence renewal paid the partner who brought that customer nothing at all, silently, while the panel went on showing the client as theirs. All of them are fixed. Seven sets of tests now hold the pieces down, five of them written as pairs that fail in both directions — break the code and they fail, quietly rewrite the promise and they fail too. Each one was checked by sabotage: remove the guard, watch the test go red, put it back.
We went looking for places where our own text promises more than our code does, and found six
It started with a switch. QA Copilot has an “off on this site” setting, and it turned off the part you can see — the panel disappeared — while the part you cannot kept running: the extension was still wrapping the page’s network calls on a site the tester had switched it off on. That is one bug, but it is also a shape, so we went looking for the same shape everywhere else: a promise made in an interface, a store listing or a privacy policy that the code does not keep. Six survived checking, and every one of them had the same cause — the rule was enforced at the main door and missing at the second, quieter one. The bridge to a coding agent limited which tabs it could ACT in, and did not limit which tabs it could READ, so an agent could ask for any tab in the browser by number. MultiLogin Tabs said session data was “cleared when the browser closes”; the cookies were, and everything the site itself stored under that session stayed on disk, including after you pressed Delete. Jig’s administrator lock stopped recipes being published and did not stop them being asked for, so a machine with sharing switched off still made a request per form. Legato’s consent card said only markup was sent, while small cut-outs of the page and the site’s name went with it, and its privacy page still described the version of the product before the repair step could reach the cloud. And Jig’s own landing page, in seven languages, promised a rail that had been deliberately removed at a tester’s request months earlier. All six are fixed — some by changing the code to match the promise, some by changing the promise to match the code, and we have said which is which in each case. Three of them are now held down by tests that fail before a release rather than after one, because the honest lesson here is that all six were written by people who meant it, and not one of them had anything checking.
Jig can now be worked in by somebody who cannot see the screen — and a real NVDA walked it to prove it
A blind tester is usually stopped not by their screen reader but by the product under test: an admin panel that cannot be used at all, so the work is physically impossible. In Jig they never go into that page by hand — they say in words what to check and an agent walks it, which turns the inaccessibility of the site under test from their problem into their finding. Making that true took four fixes. Jig now has a mode for working with a screen reader: with it on the window speaks every step of a run and reads the whole answer, not just its beginning. It had existed in the settings file for weeks with nothing anywhere to switch it on — no checkbox, no key — so the whole channel was written and unreachable; it is a checkbox now, and Alt+A from anywhere. The list of keys opens on F1, because the old shortcut needed a slash, and on the German and French layouts a slash is typed with Shift, which means that combination cannot be pressed at all on the keyboards of two of the seven languages we ship in. The window says one sentence about its keys when it opens, into the live region — invisible to everyone else, and the only way to learn the keys exist without seeing the screen. And the tour, which is the one place the product explains itself, was silent on all twenty-nine of its stops: the focus stays on the Next button, so a changing card is not an event a reader announces. It speaks every stop now. Two more things this uncovered: the welcome screen had been opening EMPTY since 18 August with no way out of it, so the product was not passable by anyone, blind or sighted; and on Windows one press of Ctrl with a digit did two things at once, switching a tab and opening a panel, announcing both. Checked with a live NVDA on real Windows and with instruments on the Mac, and the path — open a page, ask for a check, hear the run, hear the result — is now walked start to finish with nothing but a keyboard.
We drove a real screen reader through the first five minutes, and it found five places where a blind person got no answer
Until now the setup was checked by reading the markup, and markup is silent about the things that decide it: whose voice is talking, whether anything is talking at all, and whether two voices are talking at once. So there is now a stand that starts the installed build on a clean profile, switches VoiceOver on, walks the whole setup with nothing but Tab, the arrows and Return, and writes down both channels second by second — what the reader said and what the browser said, marked as spoken by us, handed to the reader, or said by nobody. The headline answer is a good one: with VoiceOver running, the browser’s own voice stays off and the reader does all the talking. Two voices happen on exactly one screen — the handover, whose entire job is to tell you that you may switch your reader off now. What it caught: the step count promised four screens to everyone, so anyone keeping their own reader heard “step 1 of 4, step 2 of 4, step 4 of 4” — a missing number, and no way to look back and find out what went past. The tour invitation had no name, so VoiceOver announced “dialogue with 3 items” and never spoke the question. The status chip announced the bare word “original” on every new tab. Return on the unavailable “Bring over from Chrome” did nothing and said nothing, which for someone listening is indistinguishable from a frozen browser. And everything the browser says about itself during setup was being written into the toolbar’s live region — a different web area, which a reader standing in the content does not read. All five are fixed in 0.3.55, along with builds for both processors, signed and notarised.
The download button now hands you something that opens — and there is a build for Intel Macs too
The Mac button had been serving a .pkg, and a .pkg was the wrong shape for this product twice over: the system installer opens a wizard with no product name in its title, and it put the browser wherever it was run from rather than into Applications. You could walk the whole wizard, hear “installation successful”, and then find no browser anywhere. It is a disk image now — the familiar window with the app on the left and a shortcut to Applications on the right — signed and notarised by Apple, so the first launch asks one ordinary question and never asks again. There are two files, one per processor: the page used to say the build would not start on an Intel Mac at all, which was true when there was one build and is not true now. If you do not know which Mac you have, the Apple menu’s “About This Mac” says either “Apple M…” or “Intel”, and with VoiceOver that window reads itself out.
The build number moved out of the window corner and into the settings
It sat in the top-left corner of every window, next to the tabs, and it was put there to answer one question during development: is this the fresh copy or the old one. That is a question you ask a handful of times in a lifetime, and answering it does not require a number in front of you all day. The corner is clear now, and the build number stands as a line in the settings, under the switch for talking about new versions — the one section that is about builds at all. Nothing else changed in this release.
The download block on the Jig page stopped saying the same thing three times
The paragraph above the buttons repeated what stood directly under them: that the Mac build is signed and notarised — which the badge three lines below already says — and that Windows is waiting for its code-signing certificate, which is the line right beneath the buttons. Read top to bottom it was the same two facts three times over, and the one thing the paragraph is actually there for, why you would leave an address at all, was buried at the end of it. That is all it says now. The Windows button itself was written out twice, once in the first screen and once in the download block, as two copies with the same classes and nothing keeping them in step — a change could land on one of them and not the other. It is one control with two call sites now, so the button at the bottom of the page cannot drift away from the button at the top.
Legato now describes the picture you are standing on, not the biggest one on the screen
Browse mode moves a reading cursor and deliberately leaves the system focus alone — NVDA and JAWS work the same way, because moving focus fires the site’s own handlers. The consequence went unnoticed for months: every command that asked “where is the person” asked the focus, and for a blind reader that answer is always empty. So “describe this image” fell through to the largest picture on the screen, the form summary and the form check each picked the container with the most fields — and could land on different forms of the same page — the table reader took the first table, and “what is this place called” recognised nothing at all. Standing on the third photo of a feed and hearing a confident description of the banner above it is a substitution the listener cannot catch. All six commands now follow the reading cursor. Inline SVG came back into reading as well: a chart with a name had been thrown out together with stylesheets and scripts, so the G key walked straight past it.
A described picture keeps its description — and the next person gets it for free
Until now a description was only spoken. The picture stayed unlabelled, your own screen reader still knew nothing about it, and tomorrow on the same page you would press the key again. Now the description becomes the picture’s alt text, so NVDA, JAWS and VoiceOver read it like any other label — and it goes into the shared memory under the same key the repair engine uses to ask about that picture for everyone else. Whoever opens the page next gets it already described: no AI call, no quota, no keypress. It is the same loop that already runs on button names, with one difference that matters — this description was made by looking at the actual image, not guessed from the markup around it. Only public pages take part, and only the detailed description: a quick skim from the cheap model would have become that picture’s permanent label for everybody.
The privacy section now says what actually travels
The page promised that the sites you open are never sent anywhere. AI repair does send the name of the site — example.com, never the path, the search terms or the order numbers — because without it the model cannot tell what kind of site it is looking at. Consent for it is also asked once rather than per page: allow it, and it keeps working on its own. Both facts are written down now. The numbers describing the limits of the engine were understated too, which is worse than it sounds for anyone checking us before an install: eleven attributes rather than ten, twenty-four ARIA roles rather than twenty-two, twenty-four interface languages rather than twenty-three. They are taken from the validator itself from now on, and a mismatch stops the site from being built.
Windows now stands in the row of download buttons on the Jig page, marked as not ready
Until today the Mac builds were buttons and Windows was a sentence underneath them, on the reasoning that a dead button pretending to be a live one is worse than a line of prose. It is the wrong way round for the person it was meant to protect: somebody arriving on Windows scans the row of buttons for their own system, finds two Macs, and leaves before reading anything below. Windows is a button now, and an honest one — it carries the word soon beside the label, it has no file behind it, and pressing it moves you to the line explaining what is being waited for, which is the code-signing certificate and nothing else. It stays reachable by keyboard rather than being switched off, because the one platform a Windows visitor came to check should not be the one control they cannot get to. It stands in the first screen too, beside the two Mac builds — and the four of them are now laid out two by two rather than in one long row, which read as a menu and ran the width of the page. Its outline is drawn in the full accent rather than a wash of it: the first cut measured 1.84:1 against the page in the light skin, and an outline IS the shape of a control — below three to one it is not a faint button, it is a button somebody cannot find.
Each of the three readings of the Jig page now has an address of its own
Since last week the page has read three ways — for someone testing by hand, for whoever ships the code, for the person who signs the requirements off — and the plates above the headline switched between them. What all three shared was one address, and a page title lives on an address: a search engine can only hold one title per URL, so whichever way you arrived, the head of the document said the page was built for QA. Somebody looking for a browser for developers met a headline that was not about them. There are three addresses now — the page itself for testing by hand, /jig/for-developers/ and /jig/for-analysts/ — each carrying its own title, its own description and its own link preview, and each one is written out in full at build time rather than assembled in the browser, because the previews in LinkedIn, Telegram and Slack read the first response and never run any script. The plates stay exactly where they were and do the same thing; they now change the address as well, so the link you copy is the one whose title matches what you were reading. Each reading also carries its own accent from now on — the teal stays with testing by hand, the code gets a violet and the requirements an amber — so the three are told apart before a word is read; only the accent moves, since the ground and the ink are what make the page legible and they were measured to be. The light in the headline behaves differently too: a wide even pool for testing by hand, a tighter source with a visible edge for the code, the softest and broadest wash for the requirements. The product being described does not change between the three — same panels, same prices, same facts — only who the page speaks to first.
Every download button on the Jig page now names the chip
Jig is two files for the Mac — one for Apple Silicon, one for Intel — and until today only the section at the bottom of the page offered the choice. The button in the hero and the one in the middle both pointed at the Apple Silicon build, so somebody on an Intel Mac downloaded a package that will not open at all. The page cannot pick for you: on Apple Silicon the browser reports itself as “Intel Mac OS X” exactly like a real Intel machine, which is why the Legato page asks the same question the same way. Both buttons now stand wherever a download is offered, each carrying its chip in the label. The line beside them was also wrong about the size: it said 137 MB for both files, where the Apple Silicon build is 131 MB and the Intel one 136 — measured against the release itself rather than a local build, which is the copy a person actually downloads. It names both now. A number like that is not decoration: it is what somebody on a metered connection decides by.
Legato can be downloaded for Mac — two buttons, because it is two files
The browser is signed with a Developer ID and notarised by Apple, so it opens on someone else’s Mac by double-clicking rather than through a trip into Security settings. There are two buttons and not one because a build for Apple Silicon does not run on an Intel Mac at all — the system refuses it, and a single file would have meant half the people downloading two hundred megabytes to be told no. We do not guess the chip either: a browser on Apple Silicon reports itself as the same “Intel Mac OS X” as a real Intel, so the person chooses and the page says which is which. What arrives is an installer rather than a disk image, and that is an accessibility decision: a disk image asks you to drag the application into Applications, and drag-and-drop cannot be done from the keyboard or described by a screen reader. The installer opens with a double click and is walked with Tab. Windows is still a waiting list — its certificate is issued by a third party and is still being validated.
Jig stops taking the same form apart twice — and now shows how much of the work runs from memory
The first pass over somebody else’s form costs real work: a hand-rolled list of divs has to be pressed, watched and understood. Jig does that once and writes it down — a procedure per control and a whole layer for the form: the order fields take values in, the knots, the places that fought back. From the second pass on it is a read from disk. Settings now carry three rings that say how much of today’s work ran from this machine’s memory, from your team’s under the same licence key, and from the shared memory — with the count of procedures collected, whole forms learned, and model calls that were not needed. The denominator is real: every control Jig filled this week, and five honest outcomes that add up to a hundred, including the one that carries most of the load — twenty-seven libraries the engine knows with no memory at all. Open an unfamiliar application and the share drops; go through it once and it climbs. Two more things changed with it: the shared memory is now served to everyone, with no key and no subscription — the base grows from those who publish, and they were never the paying half; and a form that a developer rebuilt is recognised as the same form, so what was learned moves onto the new structure and Jig says what changed — these fields appeared, those are gone.
The Jig page now reads three ways — and each one has its own voice
Jig outgrew manual QA: inside the product you say what you usually do — test by hand, write code, write requirements — and the panels arrange themselves around that answer. The landing page now does the same. Three plates above the headline switch what the page claims: the headline, the lead, the pile of windows you recognise as your own working day, the four figures, the section headings. The choice is written into the address, so `?for=analyst` is a link you can send to someone who writes requirements and it will speak to them. What does NOT change is the product: the panels, the prices, what leaves your machine and the editor bridge are the same facts for all three readers — a page that reshuffles its features per visitor is lying to two of them. Each reading also got its own forty-second narration, recorded in all seven languages with the same voices as the video series.
The catalogue lets the screenshot speak
Every product card carried an accent tile with the product’s icon pinned over the corner of its screenshot — a second mark competing with the picture that was already showing you what the product is. It is gone, in all three densities, and the dark gradient along the bottom of the shot went with it: it existed only to keep that tile legible.
Jig 1.2.3 — a quiet pause is not an error
In a conversation the microphone reopens by itself after every answer — and if you simply read the answer instead of speaking, Jig used to drop a red “no speech heard” strip into the chat right after a perfectly good exchange. An empty turn now ends the conversation quietly; the strip remains only where it is honest — dictation you started yourself that heard nothing.
Jig 1.2.2 — the voice moved into the chat
Talking to Jig no longer takes over the screen: the conversation window is now a small card inside the chat, floating just above the message box — an equaliser ring driven by the real audio level, the state in words, and a stop that is always in reach. The same card appears when you press “Read aloud” under any answer, and when answers are read out automatically. The composer stays honest about whose ear is open: the microphone button lights up only when you started dictation yourself — a conversation listening in the background shows it on the card, not on your mic button. Both Mac builds (Apple silicon and Intel) are signed, notarised and live on the download row.
Intel Macs get their own Jig build — same release, second lane
Jig 1.2.1 now ships for Intel Macs too: a separate darwin-x64 build with its own Piper synthesiser and its own locally-compiled dictation binary, signed and notarised like the Apple-silicon one. It went through the same harness before earning its download button — onboarding, projects, the voice question, five parallel chats with per-project cookie jars, and two full create→approve→confirm role chains, all green on the actual packaged app. The landing’s download row now offers both lanes; the update channel serves each architecture its own files. The QA Copilot landing also gained a link to our YouTube channel, where the product is shown working rather than described.
Jig 1.2.1 is downloadable for Mac — signed, notarised, and honest about roles
The Jig page now has a real download button: the macOS build (Apple silicon), signed and notarised, opens with a double-click. The Windows build is ready and waits only for its code-signing certificate. The release itself closes a night of hard testing on a five-app stand: a role’s cookie jar is now scoped to its project, so two roles with the same name in different projects stop sharing a session — proven with five projects on one domain and two create→approve→confirm chains running in parallel, correct signatures at every step. A run no longer mistakes its own freshly opened tab for the tester taking the wheel and stops itself. Passwords — the role form, the connection token, the HTTP gate — got an eye button that shows what you typed and never submits the form. And the “who answers you” voice question became one radio list: Jig’s own voices for your language plus this machine’s voice, which starts instantly with nothing to download; while a voice is downloading the conversation politely waits, and when it lands, the new voice announces itself.
The home page was a frame around nothing, and the index counted to one three times
The doors on the home screen — the shape the whole layout is built around — were drawn on a surface darker than the canvas behind them: 1.04:1 against their own background on the dark theme, which is not a low contrast so much as an absence of one. You saw a frame around nothing. They now sit on a raised plane that says so three ways at once: the plane itself, a highlight along the top edge, and a shadow. The type had the same problem in a different register — everything below the title lived between 9.5 and 17 pixels, seven sizes inside six, so after the heading the page had no ranks left, only texture. The scale is open again: 52 · 30 · 19 · 17 · 15 · 13 · 11. Two bugs that last week’s zoning introduced quietly went with it — the counter was reset on every list, so “01” printed three times and the numbering stopped meaning anything. The doors closed back to the same 14-pixel step the service cards stand on, because two objects next to a row of cards on a different grid read as somebody else’s page. The hairline under the promise is now the product spectrum: eleven hard segments, one per environment accent, gold through mint. Hard stops rather than a blend — a gradient would read as an ordinary rainbow, while steps say “these are products”. And the service cards themselves stopped leaning on a coloured stripe to separate them from the background: the real border was 1.3:1 against the canvas, which is to say there was no edge, and the stripe was doing all the work alone.
Switching the theme happened at four different speeds at once
The owner put it plainly: some buttons lag behind when the theme changes. Measured, it was the reverse of what it looked like — the lagging parts were the ones being animated at all. The theme button rode a 150ms default from Tailwind; on the language switch only the border and the shadow moved, so the text and the fill jumped while the frame eased; and the mark and the header’s own background had no transition whatsoever. Inside the hub there was a fourth story: surfaces morphed over 350ms against 250ms for ink, lines and accents, so text finished repainting a tenth of a second before the surface underneath it. One duration now, 200ms — fast enough that hovering does not feel sticky, slow enough that a repaint reads as a morph and not a flash. All four landing headers and the whole token morph in the hub read it from the same place, so they cannot drift apart again.
Two menu items said the same word and went to different places
In the Portal header “Privacy” led to a section of the page; in the footer, a link with exactly the same name led to the legal document. “Pricing” had the identical pair. A screen reader announces one and the same item twice and it goes somewhere else each time — the keyboard gate calls this same-name-different-target, and it is one of the few faults that holds a deploy rather than warning about it. The header now reads “Your data” and “Plans”, in all seven languages, each label checked against the legal link of the same language so the collision cannot come back through a translation. The footer is untouched on purpose: the document names there are canonical and identical across every landing we run.
This page grew to 127 entries and stopped being readable, so it now turns pages
Building in public has a side effect nobody warns you about: the record of it gets long. This feed had reached 127 entries in one unbroken scroll about 42 000 pixels tall, which is less a changelog than an endurance test. It comes in pages of 25 now, with a pager at the bottom — newer, older, the page numbers, and a line telling you where you are in the whole thing. The page you are on lives in the address, so a link to the fourth page opens on the fourth page. One deliberate decision underneath: the entries you cannot see are still in the page, just hidden, rather than left out of it. This page is what our posts link to and what the email digest is built from, and cutting a hundred shipped things out of the document to save a reader some scrolling would have been a bad trade. While we were in here, the small Shipped and Fixed labels turned out to be drawn too pale on the light theme to meet the contrast standard we hold everyone else to — 2.5:1 where 4.5:1 is the floor. They are legible now.
Your system has no API. Now it has
Qiksy Portal has a page of its own, and it is the first wedge of an idea we have been circling for a while: an agent that works inside somebody else’s web cabinet, under a login, doing what a person would do with a mouse — because the system on the other side has no API to talk to and never will. The page speaks to two audiences, and they are genuinely different people. A business running on Bitrix24 or 1C wants its own numbers out of a cabinet that will not export them; a platform vendor wants to hand its customers an integration it does not have to build. Three steps, an honest privacy section — the credentials stay on the customer’s side and nothing about their data reaches us — and draft prices while the first installations tell us what the work actually costs. Seven languages from the first day, and a card in the product catalogue marked early access, the same way Jig went out.
Thirteen environments stood in one flat list, and the list was drawn twice
The studio held thirteen environments in a single row, repeated in the rail and again on the home screen, while the grouping that would have made sense of them existed only as a comment in the registry — described, never drawn. The obvious axis was “serious versus for fun”, and it was the wrong one: Offer and Route are sold under a licence, and a caption reading “entertainment” above them talks their price down. So the split is by who pays — For business, Open to everyone, For yourself, For partners. Access moved in with the services, because an audit is quoted rather than installed, and Deal moved next to Earn, because it looks for buyers of our own catalogue, which is a partner’s job and not a customer’s purchase. The zones speak through typography and material rather than colour: ten environment accents already share one screen, seven of them in the blue-green sector, and an eleventh colour would have added noise instead of order. The personal zone sits on a recessed plate.
Nine cards offered a choice between one thing and itself
Every card in the catalogue carried two actions — “Open” and “Landing” — and on most of them both led to the same page. That was true rather than sloppy at the time: “Open” used to mean the product’s landing inside a frame under a pinned bar, and when the frames were removed last month it quietly became a redirect to the very page the other button already opened. So on Legato, a browser you download, the card asked you to choose between a page and itself. Now a product says for itself whether there is anywhere else to go. Five keep both: Qiksy Offer, Route and Deal are agents you work in, Check runs its audit in the browser you are already holding, and Access opens the workbench. The rest — Legato, Jig, QA Copilot, MultiLogin and Assist, which install elsewhere, and Pay, Build, Ops and Shift, which are pages you read — keep a single action, and it takes the accent, because one quiet link on a card that wants opening reads as a footnote. The remaining “Open” also stopped going through the front door: it points straight at the app’s address inside the studio instead of the hash route, which made the hub paint its own home page first and travel afterwards.
The catalogue never listed Shift, while everything else in the studio already did
Shift has its own page, its own place at the head of the sidebar, its own promo text in seven languages, and a partner commission that Earn has been counting since it launched. The one place it did not exist was the product catalogue — so the shelf that is supposed to hold everything we do was missing the newest thing on it, and a partner who read the rates list and then went looking for the card found nothing. It has a card now, at the end of the shelf with Access, Build and Ops, because it is sold in a conversation rather than from a checkout, and first among those three, the same order the sidebar keeps. Its copy was written straight into all seven languages rather than the three the studio started with: a card that is blank in Spanish is worse than a card that is not there, because the row around it is full. The room for questions gained the matching shelf as well — a category that does not exist is a question nobody can file. The card pictures came with it, in the full set the catalogue asks for: both design styles, both themes, both asset languages. Shift had none at all, which the page answers with a broken image rather than a blank space, and Legato’s were shot on the first of August and showed a page that has been rebuilt twice since. Both were taken again from the pages as they stand today.
One format for the settings in every header, inside the studio and outside it
The switch between the two design styles is a mark now, not a pair of words, and the mark names the era its look comes from: a bulb for the modern skin, a flame for the classic one. Sparkles and a palette, which it wore for a few hours the same day, read as “shiny” and “colours” — not what the two skins differ by. One pair across the whole studio. The three settings beside it — style, theme, language — used to sit in whatever shape each page had given them: some framed, some bare, some a capsule, one of them a sixteen-pixel glyph with no frame at all, and on four pages the language select drew a box inside its own box. They are one group now, in one fixed order — style, then theme, then language, then the button back to the studio — with ten pixels between them and a single format: a thirty-pixel square, a one-pixel frame, a body a step lighter than the page behind it, and a hover that moves the frame colour and nothing else. The corner comes from its own token rather than the card’s, because a card’s fourteen pixels on a thirty-pixel button is a circle. The studio’s own top bar follows the same rules — it was the last place that did not. And the button back to the studio is now on every landing without exception: five of them had only a text link, and Qiksy Deal had no style switch at all, so the classic skin was unreachable from that page.
The studio opens classic and light now, and the switches in every header lost their frames
Two design styles have lived here for a while — modern, which is the cold screen with depth and glow, and classic, which is warm paper by day and faded charcoal by night. Modern was what a first-time visitor got; classic is what they get now. The switch is still there and a choice already made still wins, so nothing moves for anyone who has picked. The controls themselves changed too: a header switch is a mark you press, not a plate with a box drawn around it, so the outlines came off every one of them — theme, style and language, across the whole studio and every landing. Only the switches: the status and rating chips beside them are statements rather than buttons, and a bare “★5.0” reads as text somebody forgot to finish. Two pages had a theme switch and no style switch at all, because the shared control is translated through a stack those pages deliberately do not run; they have one now, in all seven languages. And while every header was open, all nineteen were measured at eight widths in the two longest languages rather than looked at: Shift’s section links were breaking mid-word from 1120px down and its “request a review” button hung off the right edge of the window below 820; Earn’s right-hand cluster ran up to 185px past the window in Russian; the style switch pushed the catalogue’s bar onto a second row on a phone, because “Классический Современный” is 235px of labels where the English pair is 140; and one landing scrolled sideways by 18px because of a decorative glow with negative insets. All four are fixed by placing the rungs where the words actually are — the rule that a header sheds an item rather than folding onto a second line is the studio’s own, and it now holds in Russian and Ukrainian too, not only in English. The link previews were re-shot in the new skin for the same reason: a card that shows a page in a look the visitor will not meet is a preview of somewhere else. Shift got one of its own at last — it was the only landing still previewing as the shared brand logo, which is exactly what having per-page pictures was meant to stop. The style switch itself then stopped being two words and became one mark, like the theme button beside it: sparkles for the modern skin, a palette for the classic one, and the icon shows what pressing it gives you rather than where you already are. That also retired a rung — the pair was the widest control in every header (235px of labels in Russian against 140 in English) and every bar ladder had to drop it first; a 30px mark costs what its neighbour costs, so phones get the choice back. And the language menu stopped scrolling: the panel default caps any list at 280px and seven languages are exactly 280, so a scrollbar was being drawn to scroll two pixels.
The classic style is a second skin now, not the modern one with squarer corners
The studio has two design styles, and switching between them is supposed to change what the page is made of: the classic skin is a quieter palette — aged paper in daylight, soft charcoal after dark, every accent pulled most of the way toward grey, and no glow or shadow anywhere. The Shift page had been given the shape of it and none of the colour: flatter corners, a different reading face, and a palette still running at modern voltage, which is exactly what “classic” is not. It carries the real one now — the same recipe the hub itself uses, applied to the azure, the amber, the green and the ice alike — and the lit edges, the glow pools and the frosted glass come off entirely, so hairlines hold the layout instead of light. Contrast was re-measured on the new grounds rather than assumed from the old ones; all four skins pass. Two places where the switch had been leaking were closed with it: the studio kit was still painting this environment’s chips and hairlines in the full-strength blue while the page around them faded, and the very first frame of a visit was the cool modern canvas — classic is the default here, so that was the most common first frame on the page.
Two pages stopped promising a box of checkboxes and started showing the work
Both pages used to say the same thing: the same engine can be tuned to your criteria. That reads as a settings screen, and it undersells what actually happens — an industry, or a market, is not a checkbox but a separate engine. Each page now proves that with something real rather than with an adjective. Offer points at the second industry already open inside the product: care work and IT share an interface and almost nothing else — different sources, their own dictionary of 117 occupations across 25 languages, twelve card fields IT does not have, and two scoring scales with not one coefficient in common. Route points at its second market: local carriers and connection rules that live in the engine as text written for specific routes. Alongside each sits an honest note about the paid scoping session and the fixed-price modules, because “bespoke” without one costs margin. The pages themselves also stopped being brochures — the run is animated as a run: a live feed, a source counter, findings arriving with match rings, and on Route an itinerary that assembles leg by leg instead of a screenshot with the answer already in it. That is also the product’s main objection answered: twelve minutes of waiting looks like work rather than like a stall. Sections that merely restated the subheading were cut. And the Route landing finally speaks all seven studio languages: four of its addresses — Spanish, Portuguese, German, Polish — have been live and crawlable for a while, serving a translated title above an English body, which the file that generates them calls worse than not having the address at all. All 76 lines moved into the shared dictionary, the four missing languages were written, the compiler holds the symmetry now, and the four addresses were added to the sitemap, where they had never been.
One language control across every page, instead of three that did the same job
Three pages had each grown their own way to switch language. Most of the studio used a select; Shift had a two-letter button with a list under it, which reads as a badge rather than as a control; Jig had a hand-written menu with its own Escape, click-outside and focus-return — all correct, and all a second implementation of something that already existed; and Assist had a row of seven buttons, which worked at three languages and became a strip of badges wider than the navigation once there were seven. They are one control now, with a globe in front of the code so a two-letter label reads as a language rather than as any other two letters. Shift and Jig deliberately kept their own language state rather than adopting the shared component wholesale: those pages do not run an i18n stack at all — they carry typed dictionaries — and pulling one in to drive a value it does not hold would be a lot of machinery for a dropdown. The control is shared; where the state lives did not change.
Ops offered seven languages and could only speak three
The switcher on the operations-automation page listed all seven studio languages; the page itself had dictionaries for English, Russian and Ukrainian. Anything else fell back to English, so choosing Spanish, Portuguese, German or Polish changed the label on the button and nothing else — a control promising a language the page did not know. All four are now written out in full, about three hundred lines each, and the shape is enforced by the compiler: a missing line is a build error rather than a blank spot on a live page. The original rule was kept in every one of them — never name a specific messenger, marketplace or payment rail, because this line is sold in several countries and those are exactly what differ between them; the copy describes symptoms, which are the same everywhere, rather than the customer’s toolset, which would be a guess. Every other app in the studio was checked in the same pass and was already on seven, so this was the last one out of step. The step numbers on that page also lost the rectangle drawn around them: it was a shadow with no corner radius, and it is now a rule that draws itself under the number as the step arrives, continuing the same line that joins the steps into a ladder.
The money-back guarantee is 30 days now, and a refund finally switches the licence off
Outside Ukraine our payments are handled by a merchant of record, and their checkout prints its own “30 days money back” badge — worded as a maybe: an issue that makes the product unusable, and we will consider a refund. Ours said 14 days, unconditionally. Two different promises about the same purchase is the sentence a buyer quotes back at you, so ours is now both longer than theirs and still unconditional: thirty days, first purchase, any reason, nothing to explain. Once per product per person, and that limit is written down as a rule rather than left to a judgement call — because at thirty days on a plan whose term is a month, “the same guarantee applies to every renewal” quietly means a free product forever. An unwanted renewal is still refunded in full within seven days of the charge, with the subscription stopped at the same time; that is a mistake to fix, not a trial to repeat. Underneath, the part nobody sees: when a refund goes through on their side, our licence used to keep working. The money was back with the buyer, the sale still counted as revenue in the partner ledger, and a commission was owed on money we no longer had. All three are handled now, and the term comes off by exactly the term that purchase granted — never to zero, because an earlier year somebody paid for is still theirs. We also walked the checkout with a keyboard: the button that charges you shows no focus ring, and the first tab stop is a control that changes the price. Both are reported to them. That page is not ours to fix, and for a browser built for blind users it is the part that matters most.
A custom deal can now pay several partners at once, each for what they actually did
Until today a project deal had exactly one recipient, and “who splits it with whom” lived in a 300-character free-text note that somebody read by hand at payout time. That is fine with one partner and it is how partnerships fall out with two: a note has no dates, no agreements, and no percentages that cannot be rewritten afterwards. A deal can now carry up to four participants with a role each — brought it 10%, sold it 10%, runs the project 10%, keeps the client 10% for the first year — plus up to 45% for a builder who takes the fixed price and any overrun onto themselves. The totals are pools rather than a list of rates, and that is the whole point: a list breaks on the fourth person, because each new participant increases the sum and the cap starts cutting into somebody else’s money. A pool does the opposite — a new participant divides what is already set aside, so a chain has its own reason to stay short and nobody has to be turned away by hand. Commercial 40% plus production 45% plus a 15% floor for the studio adds up to a hundred, so giving away more than exists is impossible by construction rather than by validation. Shares are taken from the quote minus fees and minus pass-through costs named in the quote — third-party licences, an outside contractor, hardware: money that merely passed through us. A margin guard sits on top for the one case that matters: if both the production and three selling roles are handed outside, the selling shares are squeezed so they cannot eat more than half of what the project actually earned, and the ledger records the rate that was actually paid rather than the one that was promised. All of it is public on the Earn page, in all seven languages, because a rule a partner cannot calculate before agreeing to it is not a rule.
Shift now opens inside the studio, the way the other two service lines do
Every environment in the studio has two doors: its own page on the open web, and the same page inside the studio, where the shell draws the top bar and the rail and the environment hands over a slim header with its own sections. Shift did half of that — it hid its own header when it was inside, and stopped there. So opening it from the rail gave the page standing alone: no studio chrome, no sections in the rail, and no way back out to the full page. It was the only one of the three service lines that behaved differently from its neighbours, and three products with three habits read as three companies. Both doors work now, and the sections light up as you scroll rather than only when clicked — clicking is not the only way to arrive somewhere.
Two service pages could not be switched to a light theme — for two different reasons
Every landing in the studio carries a light/dark switch, and inside the studio the shell owns that choice and hands it to the page. Standalone, two pages were out. Build simply had no control at all: the page is dark by default and looks intentional either way, so nobody noticed the switch had never been added. Shift had one — in the markup and in the tab order the whole time — but it was rendered without a class, so it came out as a bare button: no border, no padding, an icon the colour of nothing, wedged against the language pill. Not missing, invisible; which is why it read as missing. The other fourteen pages were checked in the same pass and are fine. Shift also lost the 3D on its blue buttons: an outer glow under the button blurred its bottom edge, a white inner line along the top faked a bulge that reads as a film on a coloured fill, and the whole thing hopped a pixel under the cursor — all three growing together on hover, which is what made hovering worse than not. The buttons are flat now, and hovering answers with brightness instead of geometry.
The price calculator now shows the thing you are configuring, not a sketch of it
The panel beside the options used to be a hand-drawn wireframe — honest about being a scribble, which is a problem on a section called «configure it, watch it take shape». It is now a real interface in a browser frame: the app shell with the screens you ticked, the storefront with the pages you ticked, the assistant with the channels you ticked, and a desktop/phone switch that does not re-draw anything — the preview simply responds, which is the honest way to show that it will. It takes half the block now instead of a third, and it follows you down the options, because ticking a box at the bottom of a long column used to change a picture that had scrolled off the screen. Two options joined the list. Extra languages were always there; a light + dark theme is new at $160, and when you tick it a sun/moon control appears in the preview and actually repaints the window — showing what the line on the invoice buys beats describing it. The rest of the page grew a proof wall: thirteen things this studio has built, each with an honest label — selling, early access, still being built — and a desk that lays a week out hour by hour, from brief to live. Both service pages, Build and Ops, are also set in the studio’s own typeface now, the Latin/Cyrillic pair that carries all seven languages; Ops gained a live panel where one request walks the whole pipeline with nobody on it, and a board that converts the scattered version of today into the ordered version of afterwards while you watch.
Forms now refuse in the language of the page — not in the language of your browser
A Ukrainian page carried Ukrainian labels, a Ukrainian button, and under the empty field: “Please fill this in”. Two different things were speaking English for the same reason. Pages that check their own fields carried a two-language table and clamped the other five to English. Pages that lean on the browser’s own “this field is required” got the message in the language of the BROWSER — which stays English on most machines no matter what the visitor picked on the page. Both now draw from one dictionary that covers all seven studio languages, and it is pushed into the browser’s own message so the wording still arrives where a screen reader hears it. On a language the studio does not carry — Legato speaks twenty-four — we stay out of the way and let the browser answer, because its Japanese sentence beats our English one. Switching language also clears whatever a form is showing: a refusal is held as a finished sentence, so leaving it up after the switch means a German reader looking at a Polish complaint. The next attempt answers in the new language. Three more things surfaced while walking every form in the studio. The “tell us about the project” dialog — the one behind every “write to us” button — opened in ENGLISH on the Spanish, Portuguese, German and Polish pages, and its Send button did nothing at all, silently, if the contact could not be answered (“abc”): no mark, no message, just a button that refused. The account form — sign-up, sign-in, password reset, 116 lines of it — was in the same three languages. And on the checkout widget, the pay button and the line under it were still hard-coded Ukrainian, on the one screen where money changes hands; their translations had been sitting in the dictionary unused.
Assist speaks seven languages, and its mark now carries our own bolt
The landing had three languages while the studio had seven; Spanish, Portuguese, German and Polish have been written out in full — around a hundred and fifteen lines each, including the phone mock-ups and the price cards. Six of them now have their own crawlable address (/assist/es/, /pt/, /de/, /pl/ beside /ru/ and /uk/), each with its own title, description and cross-links, so a search in those languages can land on a page written in them. Writing them turned up something quiet: sixteen keys in the Ukrainian dictionary pointed at a heading level the page does not use, so every section heading — “How it works”, “What is inside”, the channels, “Why Telegram-first” — had been silently staying in English on the Ukrainian page. Nothing reported it; the page simply looked like a translation that had stopped halfway. Fixed and checked in a real browser. The mark changed too. The bolt inside the chat bubble was a generic “flash” glyph — the one part of the logo that belonged to nobody — and it is now the Qiksy bolt, mirrored so it runs against the bubble’s tail instead of leaning into it. The ring, the tail and the three sparks are untouched; only the bolt was lifted out and redrawn, everywhere the mark exists: the site, the app icons, the favicons, and the widget itself, where it is the face on the button your visitors press.
Team seats now step down with the size of the team
A Jig licence has always carried QA Copilot Pro for the same term, in one purchase — that part is not new and is worth restating, because it is the question people ask first. What is new is the volume ladder on team seats: $129 a seat from ten, $109 from twenty-five, $89 from fifty, against the flat $149 that applied at any size. A ten-person QA department pays $1,290 a year instead of $1,490; fifty pay $4,450 instead of $7,450. The ladder is printed on the price list rather than living only inside the checkout — a discount a buyer finds by accident is a discount that made them ask for a “company agreement” first. Teams that arrive through the new Qiksy Shift practice have their first year of seats inside the engagement: while the setup is being done the tool is part of the work, and charging for it twice would be strange. From the second year it is an ordinary licence at the prices above.
The docs now cover checking a page against its design — including what to know before reading the report
The Design panel compares what the browser renders with what the design says: paste a Figma link and you get a table of element, property, design value, page value — and the token the page value came from. “The button is painted with the pressed accent instead of the normal one” is a one-line fix; “the colour is 2% darker” is an argument. The overlay does the other half, laying the two pictures over each other with a slider, because a table can never show a block that has moved. Two caveats are documented rather than discovered later: sizes are only compared when the window width matches the frame width, since a design drawn at 1440 read in a 1600 window differs in everything, and the overlay compares blocks rather than pixels, because Figma and the browser antialias text differently and a raw pixel diff would light up every letter of a perfectly correct heading.
A new practice: helping engineering teams ship faster, without rebuilding how they work
Qiksy Shift is the studio’s third service line, and it is deliberately narrow: we do not automate testing. Autotests, CI and the pyramid stay the client’s own business. What we take is the manual half — filling a form of forty fields by hand, running the same scenario a third time, running it again in a second browser — and put it on the engines we already build, so the tester keeps testing and gets the day back. The smaller second theme is front-end: designs carry their spacing and colour as numbers, almost nobody is in the habit of reading them that way, and the task comes back from review. The page itself is new: its own palette, a console in the header that fills a form while you watch, and a request form that is real rather than decorative — three fields with validation, and the lead reaches the same inbox as every other “write to us” in the studio. Two things about that form are worth naming. The old one was three divs styled to look like fields and a mailto: link, which did nothing at all on a machine with no mail client. And when the new one was tested through our own bridge, the validation messages turned out to be invisible to a screen reader — they appeared in the markup but were never announced. Both are fixed. The page also spent a day held back from production: in the light theme the accessibility gate found 206 elements below the contrast floor, and one page was blocking every other fix from shipping. The light theme has been rebuilt since — cold neutrals instead of violet ones, a deeper accent for fills — and the gate is green. Two more gates had things to say before it could ship. The muted text in the light theme measured 3.51 against a 4.5 floor, which was most of the small print in the header console; the run log faded its lines in, and a line caught mid-fade has no contrast to measure at all, so the lines now arrive without fading. On the keyboard side the page skipped a heading level, had no “skip to content” link — the first Tab landed on the logo — and had no live region, so the form’s own error messages existed in the markup but were never spoken. Two neighbouring pages were fixed in the same pass: the chat room had no h1, so a screen reader started reading from a heading inside a column, and the Jig footer’s “Pricing” link pointed at the studio’s pricing page while the menu item of the same name jumps to a section of that landing — one name, two destinations. The page now also speaks all seven studio languages — Ukrainian, German, Spanish, Polish and Portuguese joined Russian and English, each written rather than translated key by key, down to the company, region and reference numbers in the header console, which read as local rather than as a transliterated Kyiv address. Finally, every form in the studio was walked through — twenty-two of them. Most were fine, but two of the places where someone leaves an email answered silently: the “coming soon” block that sits on products not yet for sale, and the Qiksy Pay landing. Both drew their success and error lines on screen and announced neither, so for anyone using a screen reader, pressing the button did nothing at all. Both now speak the outcome.
We audited every screen we sell from, and the partner programme was the worst offender
Four reviewers went through twenty-nine addresses — every screen inside the studio and every product page — measuring boxes and reading what the pages actually promise. The money found the biggest gaps. The earnings calculator on the partner page priced custom projects as if they were subscriptions: five Build deals showed “$5,000 a year, recurring”, where the same page, two screens down, correctly says custom work pays 10% for bringing the lead and 20% for running the sale, once, on delivery. The till had the mirror-image bug: it paid a flat half-share on every plan, including the Legato work seat where partners are promised 10% — five times too much, in the partner’s favour and out of our own margin. And the shelf and the ledger disagreed about the base: the page said “50% of every payment”, the ledger has always paid 50% of the payment minus the 6.5% card and tax fee. Two numbers about the same money is the kind of thing a partner finds on payout day, so the pages now state the base out loud and quote the figure that actually lands. QA Copilot’s trial said 14 days in the published terms, 14 on one landing and 7 on another, while the extension has granted 28 since 11 August. Qiksy Pay, Ops, Build, Jig and Legato sold from pages whose footers had no link to the terms or the refund policy at all. Referral links stopped being lost in three places: arriving straight at the Jig page counted as “came to the site” rather than “came to that product”, the Assist checkout dropped the visitor id on its way to the till, and the pricing and changelog pages did not record a referral at all. Also fixed: the light theme did not reach the studio’s own frame, so the switch looked dead on the home screen; the chat bubble spoke Ukrainian on English pages because it read the country instead of the page; the investment screen printed two different liquidity figures for one metric and a “+99,999%” that was a formatter ceiling rather than a measurement; five form fields had no name for a screen reader, two pages announced two “main” regions, and the verdict badges under every metric were below the contrast floor in all four skins.
On a phone, half the header was past the edge of the screen
Measured on a 390-pixel screen, and all of it failed silently — nothing was cut off in red, nothing overlapped, parts of the interface simply sat beyond the glass. The Settings tab was at x=458 on a 390-wide screen: a tap at its centre landed on the header, not the button, which made it the one screen on a phone you could not reach — and it is the screen that holds phone access. The language switch was given 23 pixels for three buttons 126 wide, so only EN responded and the language could not be changed at all. The earlier phone rules only tightened the gaps, and no amount of tightening fits a brand, an industry, four tabs and the right-hand cluster into 390. The header now takes two rows on a phone: the tabs get the full width of the second one and swipe sideways, the right-hand cluster gets its own. Separately, every control on the studio’s new settings page was between 26 and 30 pixels tall against the 44 a finger needs — the theme toggle worst at 26 by 26. They are shared controls that arrived from the desktop header, where a mouse-sized target is right, onto a page that exists only for phones.
Your phone can now use the engine running on your computer
Offer is local-first: your candidates, your searches and your Claude live on the machine that runs it, which is what keeps the data yours and the searches free to run. A phone has none of that, so the panel on a phone was a board that could not load — the screen it reached asked you to install an engine on a device that will never be able to run one. It can now borrow the computer you already have. Turn on “Phone access” in Offer’s settings, type the six digits it shows into qiksy.app on your phone, and the phone gets a way in. Nothing moves to our servers: your computer dials out and holds the line, requests pass through and are forgotten, and Claude keeps running on your own subscription. The code lasts ten minutes and works once, every paired phone is listed on the machine with its own way to cut it off, and the whole thing is off until you turn it on. A phone cannot open the door for another phone — new codes can only be issued at the computer itself.
On a phone the menu opened at the end of the list
Tapping the menu on a phone showed its tail — Chat, Ops, Build, Admin — while the top of the studio sat above a scroll position nobody had any reason to suspect. Two things caused it: the whole panel scrolled instead of the list inside it, and the bottom was taken up by a block of four labelled switches. The list now scrolls in its own area and opens at the top, and the bottom of the panel is a single pinned Settings row under the last product. Style, language, theme and interface size moved to their own full-screen page with a back arrow and Esc — a page rather than a route, because the same sidebar is drawn inside every product, and a route would have carried you out of the tool you were using. The desktop is unchanged.
The terms now say exactly what the shared memory sends, and what it never sends
Jig can learn a form once and remember the steps for everyone. A checkbox in the settings was the only place that said so — and a security reviewer reads the document, not the interface. The terms now state what the code actually does. Sharing needs three conditions at the same time: the checkbox, which is off by default and has to be turned on by hand; an explicitly public address, so nothing is ever sent from localhost, from an IP, or from an internal host; and a procedure that has worked twice. What leaves is the shape of the markup and the steps taken through it. What never leaves is the address, the values typed in, the text of the page, and test data. Administrators get their own switch for a whole organisation, named separately.
The studio leads with the tools it makes, not with the work it takes on
Two lists were putting the contract work first. The environment rail — which is also the order of the tiles on the home screen — opened with Ops and Build, so the first two things the studio said were both “hire us”, and the shelf of products came third. It now opens with the catalogue, then the tools themselves (Offer, Deal, Route, Investments), then the partner programme and the open rooms, with the two service lines sitting just above the back office. They lost nothing but their place at the top. In the catalogue itself the cards were ranked by ticket size, which had left Build and Ops sixth and seventh — in the middle of the shelf, between the paid products and the niche ones. Our own tools come first now: Legato, Jig, QA Copilot, MultiLogin Tabs, Pay, then the rest by maturity, and everything sold in a conversation rather than from a checkout closes the list. The free page check still stands next to the paid audit it leads into; they are now the seam between the two halves rather than neighbours in the middle. Also, the catalogue’s own description still named the three products it launched with — Legato and Jig, the two newest things we ship, were missing from it entirely.
One current Jig mark everywhere, and a light theme that stopped glaring
The favicon would not open at all, the link-preview card was a version behind, and the catalogue shots were taken against a background we no longer use — three places showing three different Jigs. They all come from the one current mark now. The light theme moved off a cold near-white onto a milk-coloured ground, with the bright patch lifted to the heading and the red deepened; that last part was not taste, the contrast gate refused the build before it.
The language list is ordered for the people reading it
The switcher still opened English, Russian, Ukrainian, Spanish — the order the dictionaries happened to arrive in, back when Russian was the only alternative we had. It now leads with English and then follows the markets the products are actually sold into, Spanish, Brazilian Portuguese, German and Polish, with Ukrainian and Russian at the end; the same order across the studio, the Jig and Legato pages and the Bench, so no two switchers disagree. Nothing about detection moved: your country still picks the language a page OPENS in, a saved choice still wins forever, and the list is read for display and nothing else.
Our landings stopped opening like a business plan
We had a voice written down and it only ever reached our posts, so the products themselves greeted people with concepts. Nine first screens now say the thing a person would actually say. QA Copilot leads with the browser you already have open — your profile, your logins, the tab you are looking at, and no second Chrome asking you to sign in again. MultiLogin is ten accounts, one window and zero incognito gymnastics. Qiksy Offer says out loud that the job hunt is brutal right now, because it is, and that the agents are there to take the grind. Access names where the problems actually live: behind the login, in checkout, in the account, in the dashboard. Business opens with the version you already survived at an agency — three weeks of discovery, six people in the chat, an invoice before anything works. Route starts at seventeen tabs and a spreadsheet. The catalogue admits every tool here was built for ourselves first. What did not change matters as much: pricing, licences, payment errors and anything you forward to your boss stay deliberately boring, and Legato, Check and Forms keep the plain voice they already had — humour on top of somebody’s hard day is not charm, it is noise. The four kaomoji we did add are wrapped so a screen reader skips them instead of spelling out punctuation. Along the way a sentence in the Jig lead that had broken in half months ago got put back together in three languages.
The studio speaks seven languages, and the language switch became a select
Spanish, Brazilian Portuguese, German and Polish join English, Russian and Ukrainian — every dictionary, not a starter set: the switcher only offers a language once all forty of them are translated for it, because a page that falls back to English mid-sentence is worse than one that never offered your language. Each was written rather than run through a translator: its own register (tú, você, Sie, ty), its own fixed vocabulary, key names taken from that country’s keyboard so a screen reader does not read “Enter” in English halfway through a German sentence, and prices left in the dollars the till actually charges. The switch itself is now a select — a row of chips works at two languages and falls over at four. Geography changed job with it: your country still picks which language the page OPENS in, but it no longer decides which ones you are allowed to see. Nine landings also gained their own crawlable addresses in each new language, with head copy written for that market instead of translated from ours. Two things this shook loose: the catalogue was printing month names from a hand-written table that had rows for three languages and would have shown a bare number to everyone else, and three of our own release gates were checking three languages out of seven while printing a tick — including one that tested “did it really translate?” by looking for Cyrillic, which a Spanish page passes by staying in English. All three now read every language we ship.
The promo kit folds up, and our own gate caught a button lying about its name
The partner kit prints every product’s copy in all seven languages the page speaks, which is thirteen products × seven cards of prose — and a partner arrives for exactly one of them. Every group now folds: a row with an arrow, the first one open, the rest closed, and the market notes closed altogether since nobody reads those end to end. The trigger sits inside the heading rather than replacing it, so the groups still form a list a screen reader can jump through. Separately, the language pill showed “RU” while telling assistive tech it was “Русский — language” — a name that does not contain what the control displays, so a voice user saying “click RU” would miss it. It passed in English and Spanish by luck (“es” hides inside “Español”) and failed on exactly the two Cyrillic pages. Found by the accessibility gate that runs before every deploy, which is the second time this month it has stopped something we could not see.
The QA Copilot that comes with Jig Pro now has a face, two links and a job of its own
Jig Pro has always included Qiksy QA Copilot Pro — the Chrome extension, $49 a year on its own — but the page said so in three sentences of prose with nowhere to click, which is how the most generous line on a pricing block ends up reading as a bundle sticker. It now shows the extension: its own mark, its own panel caught filling a seventeen-field form, its standalone price, a link to its page and a link to the store. It also says who each half is for, which is the difference between a promotion and a concept — Jig is the pass you sit down to plan, with named runs, several signed-in roles at once and the difference between last week’s run and this one; QA Copilot is the page that lands in front of you, in the browser you are already signed into, for someone checking the feature they wrote an hour ago or whoever just opened the link in a ticket. Neither half needs a model to measure: forms, findings, the network with response bodies, the WCAG audit and the Tab walk are local and free. Still one-way — a QA Copilot key does not open Jig.
The Jig page speaks seven languages all the way down, and its dividers stopped sitting on the text
Two passes over the landing. The rules meant to give every divider the same air above and below were written as bare classes, and they lost — silently — to the element rules further up the sheet, so each line kept its space underneath and had none over it. The larger one was the waitlist card: it renders its own heading, paragraph, field and button, and nothing was handing it translated copy, so “Follow the build” stayed in English on the German, Polish, Spanish, Portuguese, Russian and Ukrainian pages. Along the way: the header’s call to action no longer vanishes on a phone, the focus ring now reaches the two things that were reachable by Tab and invisible while focused, the primary button’s hover in the light theme stopped falling under the AA contrast floor, and the classic style squares the whole page rather than half of it.
The empty board now explains itself, and a run shows what it has actually been through
The board with nothing on it is the only screen a person is guaranteed to see before the product has done anything for them, and it was the most silent thing in the app. It now says what will appear there and offers one action — the same control the rail already has, not a second door to the same room — and behind the words stands the shape of a card with no data in it, so the thing being promised is visible rather than described. A run says more too: the sources it went through are named instead of counted, because “9 sources searched” asks you to take our word for it while a list of them is the proof. Chips collapse into “+N” once the strip gets long.
Black text on the main buttons inside the studio
Every primary button on the Offer desktop painted its label with the token the kit reserves for text sitting ON the accent colour — which is nearly black. Inside the studio that put dark text on a dark button; opened on its own the same screen looked right, which is why it survived this long.
A paid key now opens three installations, and the extension makes its first network call
Until this version a key had no device limit at all: the check was entirely offline, so one key pasted by a hundred people worked for a hundred people. Counting cannot be done locally by definition — an installation has no way of knowing the same key was pasted on someone else’s machine — so the count now lives on our server, and the extension asks it twice: once when a key is pasted, once a day after. It sends the key and a random number the installation generated for itself. Not a device fingerprint: Chrome gives an extension no hardware id, and assembling one out of the user agent, the screen and the fonts would mean shipping a fingerprinter inside a QA tool. That is also why a fourth installation pushes out the oldest instead of being refused — a reinstall spends a place, and a hard refusal would lock out someone who never shared anything. No page data, URLs or findings ride along, free and trial users generate no requests at all, and every key sold before today keeps working with no limit and is never asked again. The same limit now covers Offer and Route.
The paid features stopped being a list and became something you can press
Care was described in words — “the AI helps on pages the browser could not fix by itself” — which answers everything except the one question a buyer has: what do I actually get. So the page now carries a made-up website, a nature reserve, with all four problems on it at once, and a button for each. Press one and you see the answer our server really gave for that page, read aloud in the voice the browser itself speaks with: the photograph described, the officialese rewritten with every fact kept, the form explained before you start filling it, the icon buttons that a screen reader calls “button, button, button” given names. Nothing there is written by us: every answer came from a live call, in each of the twenty-four languages separately, because the model answers in your language and the page should show what it will really say in yours.
The browser now tells you when you have picked up something paid — and how long the free month has left
The question about the cloud is asked once per feature and never again, which left nothing at the moment of the press to say that this button spends something and sends something off your computer while its neighbour is free and local. Now the item says so in its own name and in a line under it, and a sound made by nothing else in the browser plays the instant the request leaves — before the wait, not after it. Next to the address there is a label while the free month is counting down and after it has run out, with the way to a key one press away; on a running Care it is not there at all, because a badge that explains a thing that works is only one more stop on the way round the toolbar. When the month does end, the feature now says so straight away instead of going to the network to be refused.
There is a room in the studio now where you can ask us about any of this
Every product had a page and none of them had a door. Now there is one: an open thread for each Qiksy product — Legato, Jig, QA Copilot, Assist, MultiLogin, Offer, Deal, Route, Access, Check, and the parts of the studio that are not products either. Anyone can write, no account needed: a login before “could you add a button?” turns away exactly the people the room exists for. We answer there ourselves, and an answer carries the question inside it, so in a thread where five people are talking it is visible who is being answered and about what. It was built to be usable without eyes from the first line rather than as an afterthought — landmarks, a keyboard route through all four areas, arrows that walk the messages, and live regions that stay quiet while you are reading further up instead of reading every arrival over you. Legato and Jig both open it from their settings, already standing in their own aisle.
The microphone in Legato stopped belonging to the operating system
Dictation used to hand you over to the system: on a Mac it worked, on Windows it did not exist, and the words went somewhere the browser could not see. Legato hears you itself now — our own build of whisper.cpp with Whisper’s weights, both MIT, running on your own computer. It works on both platforms, understands ninety-nine languages, sends nothing anywhere, and gives the words back to the browser rather than typing past it. The language pack is fetched at the first press, out loud: it says what it needs and how large it is, reads the progress as it goes, tells you when it is ready, and then simply starts listening. Measured on the same phrase, it heard “И заведи находку” where the cloud produced “И заведена ходка”.
Legato reads pages aloud itself — and the page finally says so
Legato has a voice of its own now: switch it on at first launch and the browser reads for you, free, from your own computer, in twenty-one languages. The screen reader you already use stays exactly as welcome — NVDA, JAWS, VoiceOver or Orca keep your voice, your speed, your shortcuts and your braille display, and one shortcut moves between the two in both directions. The page had been saying the opposite for months (“we do not read pages aloud and we replace nothing”), so the whole thing was rewritten in all twenty-four languages, the two sections about who speaks moved up to the top, and the spoken introduction was re-recorded from scratch — now a minute and a half rather than forty seconds, because there is more to say.
Jig’s prices now exist where money is taken, not only where it is advertised
Jig’s page has quoted three prices since it went up — a founding year, a public year, a seat for a team — and the till knew one of them. It knows all three now, the founding hundred is counted rather than promised, and a licence key finally passes the check that was silently rejecting it. The extension that the page says comes with a purchase now actually comes with it. One key opens three computers per seat, and a fourth is told so by name, with the other three listed, instead of being told the key is bad. The checkout stays shut until there is an installer for both platforms: what changed today is that the machinery behind it is real, and the prices on the page are the prices that would be charged.
Jig is signed and notarised — it opens on a stranger’s Mac now, in seven languages
Until this week Jig ran on the machines it was built on. It is signed with a Developer ID and notarised by Apple now, which means the only thing between a new user and the app is a double click — no Gatekeeper wall, no trip into System Settings, no sighted person required to get past it. That last point is the whole reason the certificate was worth the wait: the wall is exactly the kind of obstacle that stops the people we build for. The interface finished its languages in the same stretch — Spanish, Portuguese, German and Polish, 920-odd lines each, translated rather than machine-passed, which brings it to seven. The built-in walkthrough follows in all seven: fifteen stops, spoken, so a first run explains itself instead of handing over an empty window. The task queue became visible while we were in there, and stopped printing the same task twice.
The audit workbench stopped pretending an empty checklist was a clean site
Two things were wrong with it, and the second one was the serious one. First: every audit opened on the same 42-state Shopify pack, whoever the client was — a marketplace with two thousand categories and a one-product store got an identical list, in English, inside a Ukrainian interface. The scope is planned now, from the client’s own robots.txt, sitemap and harvested links: route templates, samples chosen per template, and — the part no crawler will ever find — the states that have no URL at all. The filter drawer, the gallery lightbox, the add-to-cart toast, the login modal that is a modal and not a page. For one real marketplace that came out as 20 route templates and 94 states against the old 42, and 55 of those 94 have no address. Second, and worse: the tool counted defects, and nothing counted looking. Zero findings in an area is equally consistent with “clean” and with “nobody opened it”, and a report that cannot tell those apart is how a partial audit gets sent as a finished one. So there is now a coverage axis — fifteen directions reconciled from the installed axe-core rule catalogue, Lighthouse’s own audit groups, the WCAG 2.2 specification and EN 301 549, with all 55 A/AA criteria landing in exactly one direction each. It is deliberately hard to satisfy: an untouched audit reads 0 of 15 rather than a comfortable green nothing, findings never raise coverage, a full machine pass with no human verdict still closes nothing, and a sign-off shorter than a sentence is refused. That last rule matters because of a number worth saying out loud: automation speaks to 20 of the 55 criteria. The other 35 close only by hand, and anyone promising a hundred percent automatically is selling the 20. While we were in there we ran the tool on its own panel and it failed: three contrast violations, at 4.26 and 4.32 against the 4.5 the criterion asks for. Fixed — it would be a poor exhibit for an accessibility audit otherwise.
Four more buttons that offered a conversation and opened a draft email
The same fix as on the partner page, applied to the four places that were left. Route’s “book a setup call” — the main button of a section whose entire promise is that we install the thing with you — opened an empty mail draft. The product catalogue’s “pitch your idea” called the support chat widget, and where that widget had not loaded it did nothing at all: you pressed it, the screen did not move, and nothing said why; a bare email address sat next to it as a second door. Assist’s “let’s discuss” about the native WhatsApp integration — the most valuable request on that page — was an email link. So was Qiksy Pay’s “tell us which bank”. All four are now the form the rest of the site uses: it reaches the same inbox and it says on screen that it arrived. One of them needed care rather than a search-and-replace: the Assist page translates itself by rewriting the markup React produced, which is safe only while React never re-renders that page — so the form’s open/closed state had to live outside it, or the first click on a Russian page would have restored the English text underneath. While we were in Pay we found the other half of the same problem: its entire acquirer section — the argument for which banks it works on, the legend of checkout modes, the region names, the statuses, the fee footnote — was hardcoded English on a page that otherwise switches language. Three more section subtitles turned out to have translations sitting unused in the dictionary while the page rendered its own English next to them. The whole section speaks all three languages now, and the checkout modes are named once instead of twice, so the legend and the table can no longer drift apart.
Switching theme finished at four different moments, and the panels were last
The colour swap on the home page is animated on the design tokens themselves, so anything that simply reads a token moves in step with everything else. Anything that carried its own colour transition on top did not: the target of such a transition changes on every frame of the swap, so each frame restarted a fresh chase, and the block landed about a sixth of a second after the page it sits on. On the two big product panels that is what a slow element next to a fast one looks like, and it was reported as exactly that. Making the panels slower would have made it worse; what they needed was to stop chasing. Colour is now a plain function of the token again, and what animates is the AMOUNT of hover showing — so a theme swap moves everything in the same frame while hover still eases in. The same lag was on the header icons, the sidebar rows and the footer links, quietly, because their surfaces are small; they are fixed too. Two pieces of cleanup came free with it: the active sidebar row is no longer a second pair of colours racing the hover one — it is the hover state held down, three points deeper — and the index rows dropped a special-case rule for the classic skin that existed only to say which surface the wash sits on.
The button that offered a conversation was opening a draft email
The partner program has a page for the biggest thing we offer — one country, one partner — and it ended in a button that said “write about your country”. That button opened your mail app with an empty message in it. On a computer with no mail app configured it did nothing at all: you pressed the thing the whole page had been leading to, and the screen did not move. On a computer that does have one, you were thrown out of the page into another window, and nothing ever told you whether what you sent had arrived, because a draft email cannot tell you that. The same button now opens the form the rest of the studio already uses — the one behind every “tell us about the project” on our other pages. It goes to the same inbox, reaches us the same minute, and it says on the screen that it got there. Two more doors on that page were the same shape and are fixed with it. “Request a block or info”, which partners press when a landing is missing something they need in order to sell it, used to do one of two different things depending on whether a chat widget had loaded — chat if it had, a draft email if it had not — and one of those two was silent. It is the same form now, and it carries the partner’s own code with it, so we can see whose sale is waiting on the missing block. And registering a client, which is how a partner claims a lead that never came through a link, used to hand you off to a draft email the moment the send failed — out of the form you had just filled in, with no way to simply try again. Now the page says it did not go through, the button stays where it was, and email is offered as a link you may choose rather than a place you are sent. Last, “start as a partner today” was landing people on the top of the program page, which they then had to scroll past; it goes to the registration card itself.
The site opens light now, and the gold button was never as readable as it looked
A first visit used to arrive in the dark theme. It now arrives in the light one; anyone who has already chosen keeps their choice, because the choice was always stored and the stored value still wins. That default turned out to live in twenty-one separate places — the shared hook plus a small script in the head of every page, which is what stops a page painting one theme and flipping to the other a frame later — and three landings (Assist, MultiLogin, Qiksy Pay) were not reading the shared setting at all, so they stayed dark no matter what you picked anywhere else. They read it now. What the switch exposed is the more useful half. Filled gold buttons carried near-black text, and white was not an option: white on that gold measures 2.5 to 1, which is less than half the accessibility floor, and the dark brown sitting there was the reason why. So the fill moved instead of the text — a deeper gold that carries white at 5.5 to 1 and is legible as text in its own right, which the bright one was not. Business was the last environment wearing one accent in both themes; it now follows the rule the others already did, deep fill in light and bright fill in dark. Then we checked the rest by measurement rather than by eye, and found four more buttons under the floor that nobody had reported: Route at 3.7, Investments at 4.24, Qiksy Deal in the classic skin at 4.27, and the hover state in Forms at 3.97 — that last one made the button less readable at the exact moment you pointed at it. All four are fixed. The fifth took a decision rather than a patch: the violet buttons in the dark theme sat at 4.45 against a floor of 4.5, and the same colour is the link colour on that dark background, so darkening the fill to rescue the button would have dimmed every link on the page. A colour cannot be both a fill and a link colour on a dark canvas, so those are now two separate values instead of one — a split two of our products had already made privately, now part of the shared kit and available to all of them. The violet buttons are at 6.35, the links are exactly where they were, and no button anywhere on the site is under the floor.
The browser is called Legato, and its reference page had a white frame nobody put there
Two things on the feature reference at /legato/docs/. The name first. The landing header has introduced the product as Legato on its own for a while, but the reference page, the browser tab title, every link preview and a leftover key in all twenty-four dictionaries still said Qiksy Legato — so the same product introduced itself two different ways depending on which page you arrived at. It is Legato everywhere now. Qiksy Studio still appears once, in the line naming who publishes it, because that is what that line is for. The frame second. A pale eight-pixel border ran around the entire page, and it was not a border: it was margin. The reference is a separate entry from the landing and deliberately does not load the shared stylesheet, because that sheet fixes the page height and would cut a fifteen-minute read short — and the reset that zeroes the browser’s own default margins happens to live in the same file. So the browser applied its own eight pixels, and the surface underneath was white, because the page’s paper colour is declared on an element that the margin falls outside of. On a dark page that reads as a light picture frame around everything. It is reset now, and the surface itself is painted in both themes, so dragging the page past its end no longer flashes white either. While we were in there the footer moved out of the article and became a full-width rail across the bottom of the window, matching the header — which also makes it a landmark a screen reader can jump to in one key, which it was not while it sat inside the article.
In the classic skin, Russian and Ukrainian were never in the typeface we chose
The studio has two looks, and the classic one was built on a pair of typefaces that ship Latin and Vietnamese and nothing else. Neither carries Cyrillic. So for as long as that skin has existed, every Russian and Ukrainian word in it — the body text and the numbers alike — was quietly drawn by whatever the operating system had lying around: a different typeface mid-sentence, on two of our three languages, on a skin whose entire point is that it looks deliberate. Nothing was broken enough to notice, which is why it lasted. It surfaced because we walked into exactly the same trap again while building something new, caught it there, and then went looking for how long it had been true of the old. Both faces are replaced with ones whose Cyrillic is drawn rather than borrowed, including the Ukrainian і ї є ґ. One of the two was already in the bundle for the other skin, so the site now loads fewer font files than before, not more. Separately, our own accessibility audit had been reporting eighteen failures on the dark classic skin — nine product names in the sidebar, the copyright line, seven footer links — and all of them were one grey that cleared the contrast floor against one background and missed it against the other. It is a single value, and lifting it lifts the whole skin at once. All four combinations of theme and style now pass with nothing outstanding, which has not been true before.
Our privacy policy described an architecture we no longer run
On 3 August the paid AI features moved from Claude Code running on your own computer to our own cloud, so that they work without you installing or paying for an AI tool of your own. The privacy policy did not move with them. For three days it said the opposite of what happens: that the request “does not pass through any Qiksy server, and we never see it, store it or learn from it”, and that turning on a licence key was “the only conversation Legato ever has with a Qiksy server”. Neither was true any more, on the policy page or on the product page in any of its twenty-four languages. It now says what actually happens. When you ask for one of the three AI features, that one image — or the text of that one page — goes through our server, which asks Google’s Gemini using an account of ours. The address of the page is never sent, and neither is your history nor anything you typed into a field. We also say for the first time what we keep: the answer, stored under a one-way fingerprint of the thing it describes, with nothing recorded about who asked, which is exactly what makes the same picture free for everybody the second time round. That store has no expiry date today, and we would rather write that down than round it up. One consequence follows, and we would rather say it than have you find it: a page you ask to have retold is stored as its retelling, so do not use plain words on a bank statement or a medical letter — the free repairs and your own reader are the right tools there. Nobody reported this and nobody could have found it from the outside. A browser sold to people who cannot check for themselves what it sends is worth exactly what its privacy page is worth.
Running out of plain words now has an answer, and the allowance behind it was recalculated
The monthly AI allowance a Care licence carries was checked against what it actually costs us to serve, and one of its four numbers moved: retelling a page in plain words went from 600 a month to 75. That is by far the most expensive thing we do — four times an image description — and on its own it was three quarters of the whole ceiling. Image descriptions were not touched at all: they are the one kind a blind person can never check, so they are the last place we would economise. Quick scans and form summaries came down to 1000 and 200 a month, both still well past what anyone uses. The number the grid is now built from is not the headline $49 but the cheapest seat we sell — $22 in the hundred-seat tier — because anything costing more than that seat earns would mean selling an association a loss. What makes this worth telling you rather than quietly adjusting is the other half. A ceiling you can actually reach has to have something behind it, and until today it did not: run out of retellings and the browser said “come back on the first” to somebody standing in front of a page they needed to read. There is now a free reserve of three retellings a month on top of the limit, the same idea as the ten spare image descriptions. More can be bought by the piece — 100 for $3, and they do not expire — and the browser offers that out loud at the moment you reach the ceiling, and as a button in Settings, in all twenty-four languages. The free trial month now carries forty retellings instead of twenty: the first month is when somebody who has not been able to read the web catches up on everything they could not read, which is the least typical month there is and the worst one to meter tightly.
The home page stopped being a shelf of ten identical tiles
A visitor arrived at a headline promising to find them work and clients, and directly under it got ten tiles of exactly equal size — including the back office — with nothing saying which one to open first. The two products the headline actually names now get real panels in their own colours, and everything else became a dense two-column index with a numeral per entry. The colours were always there, one per product; they had been spent on 32-pixel icon squares nobody could see. Three other things went at the same time. The logo left the workspace, because the top bar already carries it and introducing the brand twice on one screen cost a raster download to do it — the largest element on the page is now text, which paints faster than the picture it replaced. The status dot beside every product left too: in production it pings paths that always answer, so the red dots only ever appeared on a developer machine, and it marked a slow answer as a broken one — "do not know yet" was being drawn as "broken". And the display typeface was replaced, for a measurable reason rather than a matter of taste: the previous one is a very wide face whose round letters run wider than they are tall, which costs Cyrillic about three times what it costs English, and it has no small-capital forms at all, so the capitals it was drawing had no ascenders or descenders and every product name came out the same rectangle. The Russian headline was landing on three lines where English took two.
We stopped calling ourselves a studio in front of you
The word ran through the interface in three languages — "one key for the whole studio", "the studio storefront", "back to the studio", "bring clients to what the studio sells" — about 170 places in all. It is what we call ourselves between ourselves; it is not what anyone is buying. Whoever is here is buying a tool, and the word put an extra thing between them and it. In Russian and Ukrainian it also declines, so it could not be deleted mechanically without leaving broken sentences behind: every line was rewritten rather than edited. Product names are untouched — Qiksy Offer, Qiksy Deal, Qiksy Route and the rest are exactly as they were. Along the way the descriptions on the home index lost a duplicate: Ops and Build introduced themselves as "Qiksy Ops —" and "Qiksy Build —" in a line that already had the name printed beside it.
Paste a link into a chat and you now see the page, not our logo
Sharing qiksy.app/legato/ into Telegram produced the Qiksy logo; sharing qiksy.app/qa-copilot/ produced a picture of the product. The difference was not the messenger — QA Copilot was the only landing pointing its preview image at a screenshot, and the other fourteen all pointed at the same brand card. One logo cannot answer "what am I about to open" for fifteen different products, which is the entire job of a link preview. Every landing now carries a photograph of itself, shot at the proportion messengers actually render (1200×630, so nothing is cropped off the sides of the one sentence the card exists to deliver) and generated by a script, so it can be re-taken whenever a hero changes. Translated routes inherit the picture; the home page and the legal pages keep the brand card on purpose, because there "Qiksy" is the answer.
On a phone the pages could be dragged sideways, and the culprit was one invisible pixel
Every landing could be pushed left and right on a phone, taking the text off the edge of the screen — the kind of thing that reads as "unfinished" before a single word has been read. Measuring all 36 routes at 390px and 320px found six separate causes, and the largest one was invisible by design: the screen-reader-only labels in a comparison table (the words behind each ✓ and —) are 1×1 boxes positioned where they would have sat in the flow, which is inside a table far wider than a phone. With nothing positioned around them they hang off the document rather than the table's own scroller, so one pixel of width added ninety-three pixels of page. The others are rows that could not wrap: three tabs in the partner header (they now swipe as a strip), the report pager, a card whose long word made its grid column refuse to shrink, a button carrying a translated label wider than the screen, and a header where the style switch, the language pair and a large wordmark would not share 320 pixels. The site now also holds a belt for all of it — the document simply cannot scroll horizontally — using the one CSS value that does this without turning the page into a scroll container and breaking every sticky header, and without being quietly ignored by iOS Safari, which is what the old guard did.
The home page had no door a stranger could walk through, and three dead ends behind it
Every second tile on the home shelf leads to a tool that wants a local engine and a signed-in Claude CLI before it shows anything, so a visitor who has neither has nowhere to go — thirty days of the live domain produced 120 outside visits and not one second screen. Check is the one product that answers in a click with nothing installed and no account, so it is back on the shelf. The two buttons under the headline now open the tool INSIDE the studio rather than throwing the reader out to the marketing page they just came from. Three dead ends went with it. The renewal banner rose for anyone whose browser held a day counter, including people who had never paid a cent, and it printed a raw slug — "work-finder: Pro закончился" — for a product id that was renamed months ago; it now only speaks to someone who actually bought something, about a product that still exists. The "engine is offline" copy, which is read in four different places across Offer, Route and Deal, told people to run npm scripts from OUR repository; they install the engine with npx qiksy and have no repository, so it now names the engine's own commands. And a dead engine used to be visible only in Offer — Route span a search forever, Deal never asked the machine anything while idle, and Access could lock its composer so hard that only a page reload freed it. All three now notice, say so, and recover on their own when the engine comes back.
The partner rate now follows whoever does the work, instead of one number for everything
The partner offer carried a single share and applied it to every kind of deal, which broke the moment custom engineering entered it: a $3 000 MVP paid the partner $2 400 for gathering requirements and the studio $600 for building the thing. There are three rates now, each pointing at the work. Subscriptions off the shelf: 80% to the partner, because the shelf is already built and selling it is the whole job. Custom work where the partner runs the discovery themselves: 50/50. Custom work where we run it: 30/70. A partner sees the gap between 30 and 50 on their first deal, which is exactly the incentive we want on both sides. The offer also answers "I have the idea but no budget for it": we build it at our own cost when three named companies prove the demand, the scope is small, and it queues behind paid work — the partner gives up exclusivity and origination royalties, not their rate, and the product goes to the whole shelf. Separately, landing pages left the business positioning entirely. We sell engineering work — internal tools and MVPs — and a $199 landing sitting first in the estimator set the price people read everything else against.
Kazakh is the twenty-fourth language, and running out of image descriptions is no longer a wall
Kazakh gets a real recorded track, not the English one played under a Kazakh page: the usual multilingual voice does not know the language and would have read Cyrillic approximately, so the track was recorded with the model that supports it officially. The text is machine-translated and says so — the first native speaker we reach reads it over, and that is written down as a task rather than assumed. The other half is what happens when a paid user hits the monthly limit on described images. Repeating an image is free and always was — the cache is checked before anything is deducted — which is now said out loud: each picture is described once, for everyone. On top of the limit there is a small monthly reserve of ten descriptions, so nobody is left standing in front of the one image that mattered. And more can be bought by the piece: 300 for $3, which never expire. A topped-up money balance was deliberately rejected — a blind user cannot check a melting balance against images they did not see, and would start rationing three-cent decisions.
Two plans had a price, a feature list, and no way to buy them
Assist Start ($96) and Pro ($180) sat on the page with everything except a button — the only clickable thing under them was the Founding strip, which is a discount on Start. Someone convinced by Pro had to work out for themselves that their door was the cheaper offer. Both prices had been in the till since day one; the link was what was missing. In the same pass, Qiksy Offer got a demo it already had: the scene we filmed the hero video with only opened if you typed a query parameter by hand. It touches no engine and makes no outside request, which makes it the product demo the landing never had — and it is now linked from the hero and, more importantly, from the install screen, where a first-time reader hits a wall before deciding whether they want the tool at all.
The name says what we do, the mark is no longer cropped, and one number is one number
Dropping "Studio" from the name left something short and mute, so the name now travels with a line: tools that run on your own machine, automation that works for your business. It names both halves of what we sell and states the difference at the same time — the tools live with the client, not on our server. The mark itself had been silently guillotined: the lightning tail runs below the baseline into the rows where an old slogan was painted, and the fix that removed the slogan cropped from the centre because the tool ignored the offset it was given, taking sixteen rows off the top of the Q. The raster is no longer cut at all; the browser hides the slogan and the mark draws whole, with the y in the same colour as the rest of the word so the only gold left is the lightning. Finally, the MultiLogin install count was hand-written in nine places and disagreed with itself — three said 697, six said 644. It is the one number on this site anyone can verify by opening the store listing, so a mismatch does not read as a stale copy, it reads as a number nobody checks. One constant now, with the date it was last verified next to it.
The bridge sent people to a panel tab that had been renamed
Opening an isolated login needs its own confirmation — multi-login intercepts the site's cookies, session cookies included, so Agent control does not cover it. Both the docs and the refusal the bridge itself returns pointed at a "Roles" tab that the panel now calls "Logins", so the one instruction you get at the moment something refuses named a place that does not exist, and a switch looked like a broken tool. All four refusals are now written down with their causes, including the one that is not about consent at all (the tab simply is not in the session), along with the thing that actually unblocks most people: you never have to open an isolated login for an agent to work — a normal tab is enough. The reference also stopped understating the bridge: thirty-three tools, not twenty-two.
The front page described the furniture instead of saying what any of it is for
The first line of qiksy.app used to read "Your studio desktop — pick a product below." That is an instruction given to someone who has not yet been told why they would want to pick anything, and the page underneath it offered nine equally weighted tiles, which is nine ways to not decide. It now opens with what the studio is actually for — tools that find you work and clients — followed by the one sentence that matters about how they work: the agents do the searching and the checking, they show where every fact came from, and they run on your own machine rather than ours. Two buttons sit under it, one into the job search and one into the catalogue, both leading to the page that explains the product rather than dropping a stranger straight into a tool that will ask them for things they do not have yet. The nine tiles are untouched, in the same order as the rail beside them, because a home page that quietly rearranges itself teaches the same set of products twice. Three smaller things went with it. The logo lock-up carried a second slogan painted into the image — English only, invisible to search engines, and now a competing promise sitting directly above the real one — so the plain wordmark took its place, which also happens to be the element the page load time is measured by and it is a third of the weight. The description search engines print under the site had gone stale enough to name products by their old names and miss three that exist. And the strapline itself is now a real heading in all three languages instead of a picture of a sentence in one. The card messengers show when someone pastes the link was baked from that same old image, so for a while it was the last surface still making the old promise, in the one place you get a single sentence to land it — it now carries the new one as text.
Twenty-three languages, and not one of them is answered in English any more
Czech, Swedish, Danish and Finnish finish the European set: the page and the browser now speak the same twenty-three languages, which matters because a screen reader picks its voice from the language tag — get it wrong and a Finn hears Finnish read with English phonetics. Finnish is the one that shows the rule we hold ourselves to: its page had been written for a day already, and it was not offered, because the browser had no dictionary yet and promising a language the product is silent in is worse than not offering it at all. The other half of this is sound. The first thing the page does is play a forty-second track, and on ten of those languages it played the ENGLISH recording — a track is recorded, not written, so the dictionaries ran ahead of the voices. Every language now has its own: thirteen are studio recordings, and ten are synthesised with the voices the operating system ships, which are drier than a recorded voice but are at least the language the page is written in. Those ten get re-recorded and replaced. The dictionaries themselves were machine-built and then edited by a second pass that reads them as speech rather than as text, and it earns its keep — in Danish alone it found the interface calling a tab two different words, which nobody sees and everybody hears.
The browser walks you through itself, one area at a time
A browser built for screen reader users cannot be learned from a manual nobody will find, so Legato now explains itself from the inside: it dims the window, lifts one control out of the dark and says what that control does and when you would reach for it. It is not a five-slide welcome — it is 121 steps in 16 chapters, covering every button on the strip, every section of the side column, every item in the menu and every single setting, including all fifteen page fixes and all twelve sound cues. Any chapter can be skipped in one press. The point of that length is a person arriving with a problem rather than with curiosity: somewhere in there is the switch that solves it, and until now the only way to find it was to open settings and read tumblers. Three things had to be true for it to be worth shipping. It speaks to the reader first: each step is announced through a live region while focus stays on the Next button, because a reader will not re-read a button it is already sitting on, and control lives on Tab and Enter, which work in every reading mode — arrows and Escape are extras. It shows rather than tells: the repair chapter opens a deliberately broken page of our own, and to make the before honest it switches auto-repair off for those steps and forgets what it had already learned about that page, then repairs it in front of you and puts your settings back — including if you leave halfway. And it never launches itself: after installation it asks once, with "not now" standing as an equal answer, and after that it stays where you can always find it — F1, the Accessibility menu, and a button at the top of settings. Honest caveats: the tour speaks Russian only for now, and it has been proven step by step on a live window but not yet heard end to end with VoiceOver and NVDA. That listening happens before release.
A written reference for the browser, for the half of the decision the landing cannot carry
The Legato page is a paced, audio-first argument for why an assistive browser exists at all. It is the wrong shape for the other question people ask before installing a second browser — "does it do the specific thing I need, and what does Chrome do there instead?" That now has its own page at /legato/docs/, in the same form as the Assist and QA Copilot references: a long, plain document, with shortcuts written out as text rather than shown as key-cap icons, because an icon is silence to a reader. Nothing on it describes something the browser does not already do.
The agent reached for a second browser on the first unfamiliar field
We watched someone install the bridge and, at the first date picker they had not met before, their coding agent proposed wiring up a separate browser driver. Nothing was broken: the bridge drives that widget, has done for weeks, and it is written down. The problem is where it was written. An MCP server hands its manual over once, at connection time, cold, before there is a page — and what an agent does under pressure is what it can still recall. So the manual now installs itself. The first time the bridge runs in a project it writes the full guide next to the code and a short block into the file the agent reads at the start of every session, saying plainly that this browser — the real one, with the real logins — is the first tool for anything that happens in a browser, and that handing the wheel to another driver means opening an empty browser where none of those logins exist. It only writes where a project actually is, never twice, never outside its own markers, and one environment variable switches it off. The other half is that every refusal now carries its own way out: a control that will not take a value answers with the ladder to climb, and a gate that needs a human answers with which switch to flip, in the same reply as the no. And because a capability nobody names does not exist, the product page now lists what the agent can actually do — fill a whole wizard step in one call, sign in through Microsoft or Google, run several logins side by side, upload real files, read the boxes in pixels and the design token behind a colour — next to the two things it honestly cannot: take a screenshot, and run arbitrary JavaScript.
Enter confirmed a deletion while you were standing on Cancel
Every “are you sure?” in the studio comes from one shared dialog, so everything below was true everywhere it appears — including the audit panel of Access, the product we sell accessibility with. The dialog listened for Enter globally, which reads as a convenience until you arrive by keyboard: you Tab to Cancel, you press Enter on it, and the thing you came to rescue is deleted. Enter still means yes, but it is the confirm button that answers it, and focus starts there — so the key can no longer be pressed while aiming at the refusal. Three more things were wrong in the same twenty lines. The dialog had no name, and a dialog without one is announced as “dialog” and then silence: you hear that something opened, not what it is asking. Tab walked out of the modal onto the live page underneath, where every control was still reachable while supposedly blocked. And after you answered, focus went back to the top of the page instead of the button you asked from — which for a screen reader means finding your place again in a list that has just changed. Focus is handed back before the promise resolves, because the code that asked usually redraws the list immediately after, and a moment later there is nothing left to return to.
While the field was empty, the submit button did not exist for the keyboard
A defect we found on the Legato page turned out to be systemic: five forms had it, including the “follow the build” box that sits in the footer of every page we run. Each one turned the browser’s own validation off and disabled the button until the value matched our pattern. Either alone is defensible; together they make a dead end that only a keyboard shows. The form says nothing about what is wrong, because we switched off the part that would have said it — and a disabled button is not merely greyed out, it is removed from the tab order entirely. So you reach the field, press Tab, and land past the form, having never been told what it wanted. To the eye there is no defect at all: the button is right there, just pale. The browser now names the empty or malformed field itself, in the language of the operating system, which is more correct than any string of ours and needs no translating into fourteen languages. The button dims only while something is actually being sent.
Windows high contrast mode, where shapes held by a shadow have nothing to hold them
High contrast on Windows is not a theme, it is a takeover: the system strips the page of every colour it chose for itself and hands back the palette the person picked, and along the way it drops box-shadows and background gradients. That is the right behaviour, and it is also exactly the mode a large part of our audience works in every day. Half our surfaces were shaped by fill and shadow rather than by a line — so a card, a button and an input became text floating on nothing, with no edge to say where one ended and the next began. Wherever shape was carried by a fill or a shadow, there is now a border in the current colour. A selected state is told apart by the thickness of that border rather than by its colour, because in this mode our colours do not apply and arguing with the user’s would break the very thing they turned the mode on for. Focus uses the system Highlight, which they configured themselves. Honest caveat: this is measured, not yet seen — we have the geometry and the computed styles, we do not have a picture. It gets looked at on a real Windows machine with NVDA before we call it finished.
The lamp on the start screen was quietly tinted, and a tinted lens is a dim lens
On a light background a beam of light cannot be drawn in white — white on white is nothing — so the warm core of ours is mixed from the browser’s own colour, about two parts in five. That correction belongs to the beam. It was also being applied to the glass of the lens and to the hot spot right above it, which are not light but its source, and a source must not take the colour of what it emits. On the light theme the lens went a washed-out peach and the mark on the start screen visibly dulled next to its own colour swatch in settings, where the lens is left alone. The lens is plain warm white again, the same recipe the app icon, the settings swatches and the mark on this site have always used — the start screen was the only place that had drifted. The dark theme never had the problem and does not change. The body of the lamp was drifting too: it was built from two mixes, the tint with white and then with black, and on a light theme it faded away from the tint until the mark read as pale plastic beside the very swatches naming its colour. It now stands in the pure colour with a single highlight — white along the top edge, shade along the bottom — and the coloured haze that used to sit around the lamp is gone. Shape comes from the light; a third layer between them was doing nothing but muddying it.
On the light theme the lamp was invisible, because it sat underneath its own light
Legato’s mark is a lamp with a beam, and the lamp was drawn first, with the beam laid over it. On the dark theme that costs nothing: the light right at the lamp is almost the same cream as the lamp itself, so covering one with the other changes no colour anyone can see. On the light theme it erased the lamp completely. The beam near its mouth is close to opaque, so only about a fifth of the difference between the lamp and what is behind it came through — and on a pale tile that difference is already nearly nothing. A fifth of nothing is nothing, which is exactly what you saw: a dark collar, and beneath it straight into the beam, with no source anywhere. The lamp is now drawn last, and what keeps it recessed in its collar is a clip along the collar’s lower edge instead of the collar physically covering it — the same pixels, a different order. Two things went with it. The tile’s light was inside out on the light theme: the tint sat in the middle of it, and a tint is darker than paper, so the tile had a dull patch in the centre and clean white corners, which is the opposite of a lit surface. The middle is white now and the tint has moved to a faint wash at the edges. And the warm core of the beam left flat cream for amber mixed from the tint itself, because white light cannot be drawn on white. Every surface that draws the mark was changed together — start screen, welcome, search, the tab favicon, the colour swatches, the mark on this site and the window mock-up in the showcase — and every generated image was rebuilt from the same source: the app icon, the macOS and Windows icon files, the favicons, and all twenty-four tints in both themes.
Signing in became ordinary, which is the whole compliment
Resetting a password used to happen without the screen changing: you pressed “forgot your password?”, the form stayed exactly as it was, and a line of small print appeared somewhere below it. Nothing told you an email had been sent, or where, so the honest reaction was to press it again — and again. It is two proper steps now. First, where to send it. Then a screen that names the address the link went to, says which folder to check and who it comes from, and offers to send another one after a minute rather than instantly, because five presses in ten seconds is five emails and then a refusal you would read as a fault. What the server answers has not changed: identical for an address we know and one we do not, so nobody can use this door to find out who our partners are. Passwords now explain themselves while you type them, instead of a single “at least 8 characters” that tells you nothing about what is wrong. The list turns green as you go: length matters most, a digit and a symbol are required while the password is short, and from sixteen characters a plain phrase counts on its own — forcing character classes is what pushes people to Password1!, which is weaker than four ordinary words. Your own name and your own email are refused, which is the password that looks strongest to the person choosing it and falls first. Under the hood, four things that were quietly wrong: attempts were counted per network address, which protects us and not you — a pool of addresses is something you buy, while the person being attacked has one email, so the count now follows the account itself; reset emails got their own, much stricter limit, since flooding someone else’s inbox cost an attacker nothing; the cost of hashing a password went from a hundred thousand rounds to three hundred and ten thousand, written into the salt itself so older records still open and are silently re-hashed on the next successful sign-in; and an address that does not exist now takes exactly as long to refuse as one that does, because a third of a second of difference was telling anyone who asked whether an account was there. Last, there is one door instead of two: the Earn page had its own copy of the sign-in form, which would have known about none of this.
The support chat was unreachable by keyboard — on the pages about accessibility, of all places
The chat bubble sits in the bottom corner of every page we run, and its panel was hidden the way most of the web hides things: transparent and untouchable by the mouse. To an eye it was gone; to the Tab key and to a screen reader it was still there, in full, all the time. So a keyboard user walking down the page fell into a dialog they could not see — and the panel’s focus trap, which is the right thing to have in an OPEN dialog, then held them inside it. The bubble itself comes right after the panel in the page, which means it could never be reached at all. Closed now means closed: the panel leaves the tab order and the accessibility tree together, and the trap only arms while it is open. The bubble announces whether it is collapsed or expanded instead of being a nameless button, and the whole widget is a landmark, so a screen reader can jump straight to it by region rather than tabbing to the end of the page. Two more things went with it. The chat now exists on three pages that had none — Legato, Access and Check, the first two being exactly where someone reading by ear is most likely to arrive with a question. And WhatsApp and Telegram, which until today only the hub offered, are now in the menu on every page: on a page about screen readers, a live human is a better answer than a form.
Accounts stopped working today, and the form could not say why
The service that holds licences and partner accounts moved to an address of our own, api.qiksy.app, so that the string baked into an installed copy of Legato stays valid for as long as that copy lives — a blind person updates an app reluctantly, and an address tied to a worker name would die the day we renamed anything. The move was right; what we missed is that every account-shaped thing on the site still called the old address, which stopped answering. A JSON request is preflighted, and the refusal came back without the headers a preflight needs, so the browser killed each call before it left the machine. The only thing a form can say at that point is “network error” — indistinguishable from your own connection being down. Registration, log-in, changing a password and the reset mail all went at once, and the role check went with them: the studio asked who you were, got nothing, and drew the rail for a guest, so a signed-in owner lost their own tools. Every shipped surface now points at the new address, including the site’s own content security policy — a line missed there would have produced the identical “network error”, from the policy instead of the network. Failures also name themselves now: under the sentence you read there is a line you can forward us, with the host, the HTTP status and the server’s own code. And an unreachable server no longer decides who you are — “I don’t know” and “not the owner” are different answers, and only the second one is allowed to take anything away. Two smaller things went with it: “forgot your password” no longer claims to have sent a mail it did not send, and the reset page ends where it should, with a button back into Qiksy instead of a sentence asking you to type the address yourself.
The mark stopped being a sticker on the page
Legato’s mark sits on a tile, and that tile had a colour of its own — graphite in both themes at first, then warm paper on the light one. Either way it disagreed with the window behind it, because the browser has four backgrounds (two themes × two styles) and a tile with one fixed colour can only match one of them. On the light theme the effect was plain: a cream square in the middle of a cool grey page, reading as something stuck on rather than part of the product. The tile now takes the window’s own background, tint wash and all, and what gives it shape is light instead of colour — a small radial of the current tint, brightest in the middle and gone by the edges. Same recipe everywhere the mark is drawn: start screen, welcome, search, the tab favicon, the twenty-four colour swatches in settings, the mark on this site, the window mock-up in the showcase, the app icon and the OS favicons, all rebuilt in both themes. The swatches keep a stronger wash, since on a shared background the colour is the only thing telling them apart. The lamp itself is a third thicker and pushed further out of its collar — the sliver of light read as a reflection rather than as the source.
The spotlight now has something to light up
Legato’s mark is a spotlight, and until today its beam fell on nothing. Now the tile is covered in a field of small line drawings — a home, an envelope, a globe, a padlock, a printer, forty-two of them — and the light is what makes them readable: outside the beam they sit at four per cent and register as texture, inside it they come up to a third and can be told apart one by one. It is the product’s own claim rendered as a logo: the page is already there, the light is what makes it legible. Three things had to be solved to get it. The drawings are a raster set, so each one is cut out, thresholded and thinned to a hair individually — a single threshold across the sheet broke the strokes into dashes wherever the pen had pressed lighter. They are laid on a grid whose index is (row × 11 + column × 13) mod 42, which is why no drawing ever repeats along a row or a column: 11 and 13 are both coprime with 42, so it is arithmetic rather than luck. And the small sizes needed different geometry, not different opacity — at a ten-unit cell a drawing is ten pixels on a 96-pixel tile and turns to mush, so anything under 256 gets a coarser field with a thicker line, and at 32 pixels and below the drawings are dropped entirely. The light theme needed its own everything: white lines do not exist on cream, so the same image is re-inked by matrix, at its own opacities, over a plate that now sits on warm paper rather than white — a white tile beside the browser’s warm background read as a sticker rather than part of the page.
A day on one beam of light, because the mark was drawn in six places and only two of them agreed
Legato’s mark is a spotlight, and the light is supposed to run off the edge of the tile it sits on — a lamp whose beam dies in the middle of its own frame reads as an object, not as light. It did die, everywhere: the cone was already extended past the tile, but its opacity faded to zero at the end, so at the depth of the tile’s bottom-left corner — 107 of 120, because the mark is tilted twenty degrees — about five per cent of it was left. Technically the light arrived; to an eye it did not. The tail now holds twenty-six per cent and the tile’s edge is what cuts the beam, which is the only thing that reads as “it carries on past the frame”. The other half of the day went on finding that the mark is drawn by hand in six separate places — the app icon, the colour swatches in settings, the start screen, the tab favicon, the search header, the site — and that fixing the icon fixes exactly one of them. All six now share one rule: where the mark sits in a tile, the light runs to the corner; where it stands free, on a bare PNG with no edge to cut it, the light still fades to nothing, because there a beam that has not faded gets a straight razor cut along the edge of the image instead. Twenty-four tints rebuilt in both themes, plus the Windows icon and the favicons.
The page for Legato is up — the browser itself is not, and the buttons say so
Legato is a browser that repairs broken pages on your own computer so VoiceOver, NVDA or JAWS can read any site properly, and it now has a page. It opens by playing, not by explaining: a recorded human voice greets you in your own language — thirteen of them recorded so far, fourteen written, every word by hand and none machine-translated — because a page about screen readers that has to be read before it can be understood has already lost the argument. Both platforms are named on it, Windows first because that is where 86% of screen reader users are, and both buttons are marked “soon” and lead to a notify field rather than a download: there is no installer yet, and promising one to somebody who reached the button by ear would be the worst thing this page could do. We also pointed an audit at the page before shipping it, which for this product is not optional. It came back with three violations and seven defects, all now fixed: the colour swatches you use to pick the browser’s tint were eleven pixels across at 400% zoom against a twenty-four pixel minimum, the “I am paying for someone else” link was told apart from the text around it by colour alone at a contrast of 1.27 to 1 where three is the floor, the transcript toggle under the audio was twenty-one pixels tall, two nested regions announced themselves under the same name, and the sound controls sat outside every landmark on the page, so a reader navigating by region simply lost them. The layout holds from 320 pixels to 1920 without sideways scrolling, 320 being what a 1280 laptop becomes at 400% zoom — the size our own readers actually use.
We ran our own accessibility audit on ourselves, and published it
Before selling an accessibility audit it seemed fair to survive one. We pointed the same engine our free scan uses at our own production site and it returned twenty findings across six causes. The serious one: with the product rail folded, all thirteen of its buttons announced themselves as “button” and nothing else — the label was hidden with a rule that removes text from the screen reader as well as the screen, so the studio could not be navigated by voice in that state. The rest were the kind of thing no eye catches: a step number failing the contrast minimum by three hundredths, the “AI” chip on the product cards dimmed for looks below what anyone with reduced contrast sensitivity can read, a footer tagline at 2.92 to 1, and a footer link that was both too small to hit and partly covered by our own chat bubble — a click at the top of it opened the chat. All twenty are fixed, five CSS rules and one line of config, and the pages now come back clean in both rail states. The report is published as it stands, findings and fixes side by side, as the first entry in the sample gallery on the Access page: an audit shop that has never audited itself is asking you to go first.
Pages stopped jumping while they load
Every page in the studio used to shift as it finished loading — the whole body sliding eight pixels up and to the left the moment the stylesheet landed. Our own analytics scored it at 1.0 on the products catalogue, which is about as bad as that measurement goes. The cause was mundane: the rule that removes the browser’s default page margin lived in a stylesheet the browser waits for, so the first frame was drawn without it. It is now declared in the page itself, in force before anything is painted. Qiksy Offer had a second version of the same problem — the jobs view was revealed as an empty desk and then grew to full height under you — and it now waits for its first real content instead. The footer links also grew to a proper 24-pixel target while we were auditing ourselves against WCAG 2.2, which we should have done before shipping an accessibility product.
The language switch follows where you actually are
The header used to offer the same second language to everyone on earth, whether or not anyone there speaks it. Now it follows the country: English on its own in most of the world, with no switch to ignore; English and Ukrainian in Ukraine; English and Russian in the countries where Russian is the working language. Nothing became unreachable — every language still has its own URL, the search engines still index all three, and if your browser is set to Russian or Ukrainian you are offered it wherever you happen to be. Developers see all three on localhost, which is the only way to actually check the copy.
The partner rates are grouped by what you can sell today
The products-and-rates list was flat, which read as “eleven products, all equally ready” and sent new partners into their first conversation with the hardest one. It is now grouped by how each product is actually sold: what a client can start self-serve in minutes with your link crediting you automatically, what is closed in a conversation with the studio delivering, what is live but needs something true on the client’s side first, and — last, earning nothing — the free tools you use to find clients in the first place. The rates themselves are unchanged.
Hear your own page read out loud
The free page check now lets you press play on the transcript: your browser’s own voice reads the page the way a screen reader announces it, in the page’s declared language, highlighting each line as it speaks. Hearing “link. no name. link. no name.” about your own site lands differently than reading it in a table. Nothing is uploaded — the voice is the one already in your browser. The report grew a few other things while we were in there: the search result is drawn next to the chat card, with the real truncation both apply; merit badges are counted out of ten, so the ones you have not earned name themselves; the end credits list the stack the page admits to, set like film credits; and the whole report now downloads as a Markdown file or prints to PDF, which is the shape it needs to be in when you hand it to whoever owns the site. Two new numbers: how many minutes the page is out loud, and how long its HTML alone takes on a slow 3G connection.
The sample reports are now shown whole — scroll the actual deliverable
The gallery on the Access landing used to show a screenshot of each sample report’s first screen — which quietly sold a verdict line, two fix-map tables and a findings register with evidence as one thin picture. The frame now holds the report document itself, scrollable in place, with a small table of contents above it naming what you are about to scroll through. The five fictional verticals and the honest “sample, not a track record” stamp are unchanged.
The theme switches on Access and Check actually switch again
On the Access and Check landings the light/dark toggle saved your choice and then changed nothing on screen — the button wrote the preference in one spelling while the stylesheets listened for another. The classic design style had the opposite problem: it technically applied, but these two pages never carried the classic skin, so flipping the switch barely changed a thing. Both are fixed — the toggle repaints the page it is on, and classic now means what it means everywhere else in the studio: warm paper in light, soft charcoal in dark, flat corners, the quieter accent. First-time visitors also land in the modern style now, as everywhere else, instead of being seated in classic by mistake.
One tab icon for every page — and it stopped vanishing on light tabs
Every page of the studio now wears the same Q-and-bolt mark in the browser tab. Until today each product carried its own: a teal plane on Route, Assist’s own mark, and on several pages a white transparent glyph that simply disappeared against a light tab bar. The mark is now an SVG that listens to the browser theme — ink-black ring on a light tab strip, white on a dark one, the gold bolt in both — so it stays readable wherever the tab is drawn. Safari does not render SVG favicons and keeps the dark badge instead.
The audit agent chat grew into a workspace
The agent tab in the Access workbench now behaves like a real place to work, not a strip under the KPIs: the chat takes the full height of the window (the audit header scrolls away and comes back), only the log scrolls while the composer stays put, the field grows with your text, and you can dictate the task by voice — the same one microphone the rest of the studio uses. Agent replies turn every WCAG criterion they cite into a link to its W3C Understanding page. And a run no longer dies with its tab: a panel that reopens picks up the running job, and a finished run’s findings are imported even if nobody was watching when it ended.
A country is no longer bought — it is won
The entry fee for a country partnership is gone everywhere. It filtered for capital rather than for hunger, and it made the arrangement look like something it is not. Partnering starts the way it always should have: register as an Earn partner today, get your link and dashboard immediately, 50% recurring on subscriptions — no application, no waiting, nothing to pay. The lead seat for a country now goes to whoever reaches five paying clients or $1,500 in attributed revenue within ninety days. Several people may run at that at once, and the dashboard is the referee rather than a conversation with us: real clients are the whole interview. Only after the sprint is there an agreement to sign, with exclusive territory and distributor terms.
Headers that give something up instead of breaking in half
On a narrower laptop the top bar of our product pages could quietly fold onto a second row — the button you were meant to press ending up underneath the links, the page pushed down behind it. Every one of our headers now sheds what it can spare instead: the section links first, then the way back to the studio, then the design-style switch, and only on the smallest phones does the main button trade its words for its arrow. It keeps its name for screen readers when it does. The widths at which each of those happens were measured against the real labels in all three languages rather than estimated — Russian and Ukrainian run about a fifth wider than English, which is why the bars that broke, broke there first and on screens where the English page looked perfectly fine.
One product mark in every header — and controls that stopped fidgeting
The small square that names the product you are in was built seven times under three different names across the studio, so it reacted to the classic style on some pages and not on others, and inside the panels it lost its border entirely. It is one pattern now, driven by shared tokens — every header, every app, both styles. In Qiksy Offer the industry switch no longer changes size when you flip between markets: active and inactive were two differently-built boxes, and the header shifted with them. And Qiksy Deal’s search button stopped pretending: while something is still missing it dims, and pressing it marks the exact field that needs an answer instead of doing nothing.
Qiksy Access — an accessibility audit of the pages your customers actually buy on
A new service with a document as the deliverable: a WCAG 2.1 AA audit of a live store or app — including checkout and account pages behind login, which free scanners never reach — with nothing installed on the site and no overlay script. The report does not hand your developer four hundred rows; it traces every finding to the component and the design token it comes from, so fixing a handful of sources closes hundreds of findings at once. Fixed prices are on the page, and so are the limits — what an automated pass can and cannot see is stated before you ask, because roughly a third of real accessibility failures need human judgement and ours are marked as such. The audit workbench itself — the 42-state checklist, the findings register, the live fix map — is in the studio sidebar, and the free one-page Check remains the doorway: check one page for free, audit the whole store when it matters.
Selling history stopped being sending history — and the panel stopped asking everything at once
A list of letters you sent is not a record of selling: it cannot tell you which pitch and which product bring answers and which go nowhere. A candidate now moves past “sent” to “they replied” and “they bought”, one button at a time, and the board filters by those steps like any other. The panel around it was cut back to one question at a time — what you sell, who you are looking for, how many, search — with the whole console one click away when you want every setting at once. Which channels to search and how deep to dig live in settings, where they are actually remembered; on the panel they were switches that forgot what you told them after a reload. Past searches fold into their own block that always shows the last three, and the cards on the board read top to bottom again: logo, name, what the company does on its own line, what you are selling them underneath.
Searching twice now finds new ones — instead of paying again for the same list
Both hunters had the same blind spot: run the same brief a second time and the agent ran the same queries against the same web, so most of what came back was what you already had. Qiksy Deal now tells the agent which companies are already on your board and, more importantly, that skipping one does not use up a slot — so the places freed up get filled with new names rather than quietly shrinking the list. It also has a floor on effort before it may claim a niche is finished: several genuinely different searches — other towns, the local wording, the local language, smaller catalogues — and it reports which queries it actually ran, so “there is nobody left” can be told apart from “it did not look”. And when a niche really is worked through, pressing search again says so before the run starts instead of after twenty minutes of waiting; you can still run it anyway, and the note clears itself after a week, because new businesses appear. Qiksy Offer gained the same warning for a role whose market is exhausted — it used to spend two full sweeps rediscovering that — and it drops the warning the moment you change the keywords, the regions or how fresh a posting has to be, because that is a different question.
Qiksy Check — see one page the way everyone who is not you sees it
A new free tool, and the only one here that asks nothing of you: no account, no key, nothing to install. Paste an address and it reports what a screen reader can and cannot use, what a search engine and a link preview make of the page, and how it is served — twenty-six checks, each with the reason it matters instead of a rule number. It also shows what a score cannot: the page read OUT LOUD in the order it is announced, with everything that has no name marked; the exact card the link turns into in Slack, LinkedIn or Telegram; the outline people actually navigate by; and every other company the page loads something from, with the recognisable trackers named. The audit runs in your own browser — we fetch the page’s HTML and nothing else, and keep none of it. It is honest about its limits too: colour contrast, JavaScript errors and failed requests need the page to actually run, and that is what QA Copilot is for.
Work Finder is now Qiksy Offer — and the road from “add me” to a running search stopped having holes in it
The name says what you are actually after. Nobody wants a list of vacancies; people want an offer — and that is the thing the tool works towards, from your résumé to the letter that goes out. Same tool, same data, nothing to migrate, and the address you have bookmarked still works. Behind the name, a full pass over the newcomer’s path fixed the places where the product knew something and did not act on it. A candidate dictated in one market no longer lands in another and disappears; roles now attach to the person rather than to whichever board was on screen. What you said out loud arrives already ticked — the country you live in, the city, a language level, whether your diploma is recognised — instead of being asked again two screens later. Nothing blocks a search silently any more: a run that finds nothing says so and stays in the history, a role that fails says why, counts stop including dead links the engine itself struck out, and the local engine dying mid-run is now visible within seconds instead of leaving a stopwatch running for hours. Where an answer really is missing, the card takes you to that field and holds an amber mark on it until you get there.
Creating a candidate stops guessing — at the country, at the limit, and at the city you said out loud
Four things went wrong on the way to a first candidate, and all four are fixed. The target country was a free-text box, so a typo quietly narrowed the search to nothing; it is a list now. A profile that was saved without everything the search needs used to vanish from the column — it stays there, marked, and pressing it opens the very fields that are missing instead of a general "something is incomplete". Everything that blocks a search now sends you to the candidate’s own card — never back into the résumé builder you just left — with the missing answers lit up in amber, the address field among them, opened and focused so you can type it where you are standing. That holds when the refusal comes from the engine rather than the panel, too: it used to be a dead end with a message in the wrong language. And a city you mentioned while dictating your story — "I want to work in Berlin" — now reaches the search: it used to be heard and dropped, which is how a Berlin request came back with Switzerland.
You can follow the build by email now, from Qiksy Offer and Assist too
We are building Qiksy in the open, and until now the only way to hear about it was to happen to come back. The short "follow the build" box — one field, no account — was on the catalog, QA Copilot, Business and this changelog; it is now also at the bottom of the Qiksy Offer and Assist pages, in all three languages. One list, not one per page, and it exists to send a note when something actually ships.
The renewal reminder closes now — including the one that says your term has ended
Nothing here renews by itself, so the studio speaks up a week, three days and a day before a licence runs out, and once more after it has. The “ends soon” bars could be dismissed; the “your Pro has ended” bar could not, and a notice you are unable to close stops being information. Every one of them now has a × on the right, and closing it is remembered through reloads. It comes back only when the news actually changes — dismissing the week-ahead warning no longer silences the day-before one, which is what used to happen, and renewing starts the count over. Close the “ended” bar and it is gone for good; the quiet mark next to the tool in the sidebar still says where you stand.
Dictation works on the site again — we were blocking our own microphone
Speaking your story into the profile builder failed on qiksy.app with “the microphone is blocked”, and it failed for people who had never blocked anything: one of the site’s own security headers switched the microphone off for every page here, so the browser refused before it could even ask you. That header now allows the microphone on our own pages — and nothing else gained access; the camera stays off, as it was. If you do deny the mic yourself, the message points at the address bar, which is where the switch actually is.
Picking a market no longer blurs the form you are filling in
Switching between IT and healthcare on the “create your profile” screen dimmed the whole card and put a spinner over it — a wait staged for a board full of finds, on a screen that has none, with the spinner sitting off the card’s centre. The choice now lands immediately. The two markets also carry their own colour everywhere they show up — blue for IT, green for healthcare — so which one you are filling the form in is readable without reading. Inside the tool, where switching really does swap a full board, the soft blur stays.
Two markets, two boards — a nurse can no longer show up in a developer’s list
Qiksy Offer hunts in two markets, IT and healthcare, and the industry used to be just a label on the candidate: every part of the panel had to filter out the other market by itself, and one of them never did — the “add a candidate” picker offered a care worker in the middle of a full-stack search. Each market now has its own space in the database on your machine: candidates, roles, finds, leads and search history are kept apart, so there is nothing left to leak. Switching markets loads its own board behind a soft blur instead of flashing an empty screen, and the search settings you tune — freshness, channels, how many results per sweep — stay with the market you set them in. Your existing data is split automatically on the first run, with a copy of the old file kept beside it.
Telling us about a project is a form now, not a draft email
Every "start a project" and "book an audit" button opened your mail client with a half-written letter in it — and on a machine with no mail client set up, it did nothing visible at all. They now open a short form: a couple of lines, a way to reach you, and a file if you have one. The estimate the calculator builds rides along as a real PDF attachment instead of landing in your downloads folder, and the message goes straight to the people who answer it.
MultiLogin Tabs has a privacy policy you can actually open
The policy linked from the store listing pointed at a page that had gone missing, and a privacy policy nobody can read is not a privacy policy. MultiLogin now has its own at qiksy.app/multilogin/privacy/, written for THIS extension instead of borrowed from another one: exactly what it touches (cookies, localStorage, IndexedDB and Cache Storage, isolated per tab), where that stays (your browser, and nowhere else), and what each permission is really for. It also says the limit out loud: this is a best-effort container built from header rewriting and JavaScript virtualization, not a true browser container.
Every page can now reach a person, not just five of them
The chat bubble lived on the hub, Business, the catalog and two product pages — so a question that came up on Pay, Forms, MultiLogin, the partner program, the radar or the pricing page had nowhere to go. It is on all of them now, and it is the same Qiksy Assist we sell: the message lands in a Telegram chat and the reply comes back into the widget. The three working tools — Qiksy Offer, Qiksy Deal and Route — are deliberately left alone: they are what you already paid for, not a place to be sold to.
A long prompt in the message box no longer looks broken
When the assistant asked something wordy, the hint inside the empty message box wrapped onto a second line and put a scrollbar into a field nobody had typed in yet. It now cuts off with an ellipsis instead — and the moment you start writing, the box wraps and grows exactly as before.
Pages stopped throwing you back to the top while you read
Scrolling a page inside the studio would snap back to the very top every screen or so, which made anything below the first section effectively unreadable. The page was not scrolling itself: the studio frame around it was being rebuilt from scratch as you crossed each section, and a freshly built frame starts at the top. It is now updated instead of rebuilt, so the scroll position — and everything else the page was holding — survives. Checked on every landing in the studio.
Care work is free now — the people who need the search most were the ones locked out
Healthcare and care used to be a paid industry: on the free plan only IT worked. That protected the wrong side. Germany’s own labour figures say the qualified nursing layer is short of PEOPLE — 57 unemployed per 100 vacancies — while the layer without a recognised diploma is the crowded one, at 2 131 per 100. The person for whom finding a posting is genuinely hard was the only person we would not let in. Free now covers one candidate in care exactly as in IT: local job titles, region by region, language level and diploma recognition read off every posting. What is paid stays paid — several people at once, and the agent working while you are away.
Team: the more seats, the cheaper each one
Seats were a flat $99 a year, which meant an agency working with two hundred people saw a five-figure number and stopped reading. A seat is also less than it sounds: it is a concurrent slot, freed the moment someone is placed and removed, so a handful of seats carries a much bigger yearly flow. Now the price steps down with volume — $69 a seat from ten, $49 from twenty-five, $35 from fifty — on one rule: a year of the licence must cost less than a single placement, at any size. And nobody pays more for less: a ladder like that would otherwise make twenty-four seats cost more than twenty-five, so when the next step is cheaper in total you simply get that step — more seats, less money.
A candidate may list every job title they actually do — on the free plan too
One person is often three postings: a care worker is advertised as “Pflegehelfer”, “Betreuungskraft” and “Alltagsbegleiter”, and a developer answers to two or three titles as well. Roles stopped being something you pay for — every plan now carries the same generous cap, because a board built on a single title is too thin to show what the tool does. What you pay for is automation (auto-apply, leads, scheduled monitoring) and the number of people you are hunting for. Engine 1.7.2 on npm.
Engine 1.7.1 — a mistyped licence key now says so
A key with a typo, a stray space or a missing character used to report “could not verify — check your connection”, sending people to fix their wi-fi instead of re-reading the key. The engine now tells the two apart: a key we reject is a key problem, and only a real network failure is reported as one. `npx qiksy` picks it up on the next run.
A walkthrough that builds a profile in front of you
First run now starts with one question — IT or healthcare — and then offers to show you the tool working, on invented data, before you type anything of your own. The walkthrough drives the real screen: it opens the résumé builder, tells its story into the field, watches Claude assemble the profile and name what is missing, then hunts, opens a find and sends the application. Say no and it waits behind a bar at the top; the compass in the header replays it any time.
The first frame no longer says your board is empty
Reloading with candidates in place used to flash “create your profile” for a moment before the data arrived — the app could not tell “nothing here” from “nothing yet”. It now remembers that a board exists and shows placeholders until the engine answers. The browser-status pill stopped flashing red for the same reason: not asked yet is not the same as disconnected.
Describe a candidate in one sentence — the card asks for the rest
Type or dictate one sentence and the candidate card fills itself in: profession from the catalogue, country, region, language level. Whatever is still missing becomes a question with the answers ready, instead of a list of complaints you have no way to act on.
Engine 1.7.0 on npm
`npx qiksy` now carries industries, regions and the whole care vertical, so a local install gets them without waiting for anything else.
Healthcare and care work, searched the way that market actually works
A second industry alongside IT: vacancies are searched by the profession’s LOCAL name in the country you picked, region by region, and scored on the things that decide a care job — the language level the posting demands, whether a diploma has to be recognised before you may start, housing and visa support.
Search by region, not just by country
An offline job is an address. Countries now open into their own administrative divisions — states, oblasts, federal states, voivodeships — with the word each country actually uses, so a search for Bavaria stops meaning “somewhere in Germany”.
Move your data to another machine without a cloud in between
Candidates, résumés and finds export to a file and import on the next machine. Nothing passes through us on the way — the tool is local, and moving it should not be the one moment it stops being local.
The landing shows the real panel, and a walkthrough runs the whole job
The page you land on now shows the actual working board instead of a drawing of one, and the guided walkthrough goes end to end — candidate, search, finds, letter — rather than stopping halfway.
Qiksy Forms — announced, in development
A tool that opens an official form and fills it in while you answer out loud, on your own Claude, on your own machine. It is being built, not sold yet: the page says so plainly and takes an email for the day it works.
Follow the build — one email, no algorithm
Added a “follow the build” signup across the studio, so you can watch Qiksy grow from your own inbox instead of hoping a feed shows it to you. No spam, leave whenever.
A name, not a code
Qiksy Assist now asks a visitor’s name before the chat starts, and tells two people with the same name apart — so the person on the other end is a real conversation, not an anonymous ticket number.
Rebuilt as one live agent
Qiksy Offer became a single “live agent”: a search that narrates itself in real time, vacancy cards with a 0–100 match ring, and a calmer royal-blue look. It runs on your own machine, on your own Claude sign-in — we hold no key.
Your tools, your key
Every AI tool now runs on your own Claude sign-in. No key to hand us, nothing billed through us, and your data never leaves your machine.
Two-way chat, live in production
Qiksy Assist went live: one script tag turns any website into a two-way chat that lands straight in your Telegram — you answer from your phone, the visitor sees it in the widget.
★5.0, and free forever
MultiLogin Tabs keeps every account in its own fully isolated tab — cookies, storage, the lot. ★5.0 from ~700 real users, free forever. Small, but real, and we’ll never quote a bigger number than the true one.
Keys that verify themselves
Stood up the licensing service so the local-first tools can unlock by key, verified against their own worker — kept deliberately separate from everything else.
Follow the build
We're building Qiksy in the open — new tools, real progress, the occasional stumble. Get the short note when something ships.