Selected work
Four projects from 2026, each with the method and the measured result.
All four are my own projects, so I can go into every detail of the method. Client work is confidential and is described only in general terms on the home page. Apart from ClaudeMail, which is on GitHub, no source code is published here.
A neural voice that runs on the iPhone
- What
- Inklight, an iPhone and iPad app that reads your own books aloud with a neural voice (Kyutai Pocket TTS) generated on the device, offline.
- My part
- All of it: profiling, optimization, measurement and the app.
- Status
- On the App Store.
The starting point was an open-source port of the speech model to iOS. A phone has to generate speech faster than it plays, for hours, with the screen locked, and without iOS killing the app for its memory or CPU use. The oldest supported phone is an iPhone XS from 2018.
I profiled every stage of the model on two phones (iPhone XS and iPhone 16 Pro) and compared CPU, GPU and Neural Engine backends in interleaved runs, which cancels out thermal throttling. Every speedup that changed the numbers was checked by its error against the full-precision model and by listening. Energy I read from the kernel's per-process counters, so measuring one configuration takes a minute instead of a 20-minute battery run.
Results
- Speed on the iPhone 16 Pro: 3.51x real time with the unmodified engine, 6.08x after quantization and other CPU work, 7.25x with part of the model on the GPU. On the iPhone XS: from 1.62x to 2.15x.
- 8-bit quantization: 0.5-2% relative error per layer. Memory on the XS went from 795 MB to 347 MB, and the model download from 235 MB to 130 MB.
- A Neural Engine version needed only 185 MB at 4.98x real time, but it did not pass the listening test, so I dropped it.
- The app was killed when a single sentence ran past about 16 seconds of audio (2,098 MB against a 2,097 MB limit on the XS). Memory grew with the square of the audio length. I derived the formula, confirmed it with measured peaks and fixed it.
- CPU energy per second of speech on the 16 Pro: from 1.03-1.15 J to 0.21 J, about five times less, while still running at 2.2x real time (the kernel's estimate, CPU only).
- Playback with the screen locked on the 16 Pro: 924 mW, about 14.7 hours from a full battery.
The Inklight page plays samples of every narrator. The app's code is not public.
Forecasts that run a home battery
- What
- A planner that decides every hour when a 16 kWh home battery charges and discharges, from forecasts of sunshine, solar yield and electricity prices.
- My part
- All of it, from the data pipeline to the controller.
- Status
- Controls the real battery every hour since 2026-10-21.
- Methods
- Gradient-boosted quantile models, Bayesian model averaging, a Gaussian copula, linear programming. Python.
The data: weather forecasts from four models (GFS, ICON, ECMWF, MET Nordic) as they were issued at the time, the sunshine as analyzed afterwards (ERA5 reanalysis and SMHI's 2.5 km grid), Swedish day-ahead prices, the inverters' own logs and the electricity invoices. One inverter lost its connection for long stretches. I rebuilt its missing hours with quantile models and a Gaussian copula that keeps the hours of one day consistent with each other, scaled to match the inverter's own energy counter.
Validation uses one fold per calendar month, with tests that no forecast sees data from after the time it was issued. The scores are mean absolute error, pinball loss and how often the actual value falls inside the 80% band. A second, independent check rebuilt the cleaned inverter tables from the raw exports (identical in all 196,992 values) and found no leak of later data into any forecast.
Results
- Sunshine, one day ahead: mean absolute error 39.7 W/m², against 84.4 for the seasonal average. The 80% band of that model held only 74% of the actual values, so it was too narrow. Bayesian model averaging reaches 85% at nearly the same error (39.9).
- Daily solar yield, one day ahead: off by 4.1 kWh on a mean day of 24.9 kWh (seasonal average: 9.1 kWh). Fed with the actual weather instead, the error is still 4.1 kWh, so what remains is in the step from weather to yield, not in the forecast.
- Missing inverter hours: on test days that I hid from the model, 80.2% of the hours fell inside the 80% band (75.9% without two widening factors that were fitted on the same data).
- Battery backtest over 873 days: the plan made on forecasts comes within 260 SEK a year of a plan made with perfect hindsight.
- The bottom line is smaller than it first looked: under the current electricity contract the planner gains about 1,000-1,100 SEK a year over the inverter's built-in logic, before battery wear. A wear cost of 0.66 SEK per extra kWh charged would cancel it.
Can a judge tell the AI imitation apart?
- What
- A prompt that makes a language model write in one person's voice (mine), and the harness that measures how well it works.
- My part
- All of it.
- Status
- Research, last iteration in September 2026.
- Methods
- Stratified corpus, dev and test holdouts, a blind LLM judge, a leak check. Python, Claude Opus 4.8 as writer and as judge.
"Write like me" is easy to ask for and hard to check, because every prompt looks convincing to the person who wrote it. So I built the judge before the prompt. The judge sees three real samples of the register, then a real text and an imitation in both orders (that cancels its measured bias toward the first one), and names the real one. 100% means the imitation is always caught, 50% means the judge cannot tell them apart.
The prompt is built from a corpus of about 3,000 samples of my own writing. It is judged on 31 other texts that I iterated against (the dev set) and on 31 more that were never shown to the critique step or used in writing the prompt (the test set). A leak check verifies that a prompt quotes nothing from the held-out texts. Version 2 failed it: 23 phrases from the held-out texts had come in through the critique step, so its score was worthless. It stays in the results table, marked as contaminated.
Results
- Dev set, 62 trials per version: version 1 was spotted 66% of the time, version 4 61%. At this size, differences below about 10 points are noise.
- Test set: 53% for version 1 and 52% for version 4. Both are at chance, so the test set cannot separate them.
- Recent careful writing only, 50 trials: 78% spotted with the general prompt, 66% with a prompt built for this register.
The lesson: build the judge and the leak check before the thing being judged. The corpus is private (diaries and chats), so only the method and the numbers are shown here.
Mail between Claude sessions
- What
- ClaudeMail, a mail system for Claude Code sessions. A session on one computer picks a session on another (or asks for a new one) and sends it a message, which arrives as a visible turn in the Claude Code desktop app.
- My part
- The requirements, the design decisions and the reviews. Claude Code sessions wrote, tested and repaired the code at my direction.
- Status
- Runs every day since 2026-09-24, on all eight machines of the house (four Windows PCs, four Macs) since 2026-11-09. Public on GitHub under the MIT license.
- Methods
- Failure audits by message count, independent review agents, tests against a control copy of the old code. Python (standard library only), Resilio Sync as the transport.
The first version took six minutes to write. Making mail reliably reach the right session took seven weeks and four designs, and each redesign followed a review that counted failures or messages. The fix that worked was to stop the receiving machine from guessing: the sender now asks which sessions exist on the other computer and picks one, or asks for a new one.
Results
- Mail in the wrong session: 16% of 371 messages with the second design (27% of replies). After version 4, 355 of 358 messages were delivered, none to the wrong session, with a median of 12 s.
- Live tests of version 4: a running session answered in 7 s, a new session had its mail 4 s after it arrived, and a closed one answered 9 s after it was reopened.
- Independent review agents found 8, 10 and 2 serious defects in the first candidates of three later deploys, all fixed before the deploy.
- About 2,700 messages filed since 2026-09-24, 1,081 of them in the first 13 days of November.
The full story tells how it got there and what the sessions send each other now. The code is on GitHub.
Industry work
Five years of inspection AI at SICK and Woodeye are under track record on the home page: a light-knot detector for oak that went from a six-month prototype into production, and adversarial test sets for an embedded smart camera. In 2026 I worked as a forward deployed AI engineer for NineTwoThree, a US AI agency, embedded with its clients; that work is confidential and is described under other work.
For questions about any of these projects, write to info@volary.pro.