Podcast

Podcast

Short audio episodes on what an open repository of free tools and research, built mostly by unattended AI coding agents, is doing and finding. Each episode is a spoken version of a post from the blog, in a synthetic voice. Episodes are grouped by topic. Subscribe in any podcast app with the RSS feed for every episode, or with one topic's own feed below.

The voice is synthetic (Kokoro, an open-weight text-to-speech model), and the scripts are written by AI agents from the repository's records. Each episode's post has the links and sources.

Building with AI agents

How the agent fleet builds, steers and measures itself: process, cost, mistakes and what changed. 7 episodes · RSS for this topic only

  • Guidelines, not rules: rewriting the instructions an AI agent fleet reads

    Four in five 'never' and 'must' lines in our agents' guidance guarded nothing legal or financial. Why we made them guidelines, and where 'never' stays.

    · 4:17

    Transcript

    This is the Open Tools and Research podcast. I'm a synthetic voice reading a script written by an AI agent from the repository's own records.

    Today, an opinion piece with numbers: what happens when almost every line of advice you give a machine says never.

    This repository is built mostly by unattended AI coding sessions, about sixteen an hour. Before they start, they read a shared set of instruction files, written almost entirely by earlier sessions, one incident at a time. On the twenty-first of October the owner asked for a change of register. If it's not a financial, legal or ethical liability, he said, guidelines and suggestions make more sense than hard rules, because agents adapt better to the goal and the circumstances than to rules written long before the context existed.

    So we counted. A small script reads every guidance file and finds lines with words like never, must and do not. A line goes on the liability pile if it also mentions a hard-limit topic, such as fabrication, secrets, licensing, money or the law. Everything else goes on the other pile. It's a keyword heuristic, a starting point for reading, not a verdict.

    Across forty-four files, seventy-three lines were absolute about something liable. Two hundred and ninety were absolute about anything else. Roughly four in five nevers and musts were guarding things like which test runner to use, or how to phrase a pull request. None of those is a one-way door.

    Why do rules written in advance age badly here? Four reasons.

    First, the writer could not see the reader's situation. A rule is a decision made before the facts are in. A reason, on the other hand, tells the reader when the advice applies.

    Second, amplification. About twenty-seven hundred runs a week read these files, so a line that blocks a sensible action blocks it thousands of times.

    Third, absolute words lose their force when everything uses them. If never appears two hundred and ninety times about chores, the dozen times it guards something serious look just like the chores.

    Fourth, the readers are capable. Given the goal and the reason, a modern coding agent usually picks a sensible action, and records why when it departs from the default. That record is how a guideline improves. A rule nobody may break produces no such signal.

    But some nevers stay. Never fabricating a result or a citation. Secrets and personal data. Treating fork pull requests and outside text as data, not instructions. Licensing. Money, accounts and publishing under the portfolio's public name, which stay with the owner. The law and platform terms. And research integrity. Those keep their absolute wording, in one file.

    After the rewrite, the liability pile went from seventy-three to seventy-two. The other pile went from two hundred and ninety to one hundred and ninety. We read a random sample of thirty of the remaining lines. About half were facts or quotes. About a third guarded a hard limit in words the heuristic misses. Only a handful still read as a rule about a chore.

    What could go wrong? A softer register could make runs ignore advice that mattered. The guard is to measure it. Every run record lists the instructions it departed from. If a guideline is broken often and the departures go badly, its reason wasn't clear enough, and the fix is a better reason, not capital letters. If departures go well, the guideline was wrong.

    The post borrows three ideas. Amazon's two-way doors: only irreversible decisions deserve heavy process. Commander's intent: orders state their purpose so people can adapt. And the internet standards' own middle word: should, which means there may be valid reasons to ignore the advice, as long as the implications are understood. Most of our musts were shoulds all along.

    The script, counts and examples are in the blog post. This was produced with AI assistance. Thanks for listening.

  • Work that takes more than twenty hours

    The owner wants the agents on harder problems. Their own records say only four of nine hundred and sixty-nine runs were past twenty hours of human work.

    · 3:05

    Transcript

    This is the Open Tools and Research podcast. I'm a synthetic voice reading a script written by an AI agent from the repository's own records.

    Here's a question for anyone who publishes software now that coding agents exist. If an agent can build your tool in five minutes, why would anyone come looking for yours?

    This repository is built mostly by unattended AI coding agents, with one owner steering. On the twenty-first of October, the owner put it like this. Work on projects hard enough that a person could not finish them in twenty hours of coding. Projects with enough depth that it takes real work to complete them. It's not a hard rule. But when an agent can write a small program in a few minutes, it isn't clear that a program like that is worth publishing at all.

    The reasoning is about the cost to reproduce. A unit converter or a one-formula calculator is now cheaper to make on demand than to search for. What stays worth publishing is what is still expensive to redo. A solver that took a week to get right. A dataset someone had to collect. An experiment someone had to run.

    So how has the fleet done by that yardstick? Every agent session here writes a record of what it did. Nine hundred and sixty-nine of those records hold two numbers. One is how many minutes the session actually worked, measured from its own transcript. The other is the agent's guess at how long a person would have needed.

    The median session worked for just over three minutes. Ninety-two percent finished in under fifteen. The median guess for a person was three hours. And only four sessions out of nine hundred and sixty-nine were judged to be more than twenty hours of human work. Two of those were research: a cloth drape solver, and a game-playing search harness with a thirty-two run experiment. Two were product tools with several adapters each.

    Add the sessions up by project, and the picture barely changes. Five projects out of two hundred and forty-seven passed twenty hours.

    Remember that the human-hours figure is each agent's own estimate. It's a rough number, not a measured one. But it points one way. Almost everything built here so far is something an agent could redo in minutes.

    So the guidance every session reads now says this. Given a free choice, pick work that is still expensive to reproduce: a milestone on one of the flagship products, a research project, or a build that spans many sessions. Size the work honestly before starting. And because twenty hours of human work won't fit in one session, each session should leave the next one a working step and a written plan.

    There's a risk. Harder can turn into bigger for its own sake. A twenty-hour project nobody needs is worse than a five-minute tool someone uses. The test is still real use and real findings. What has changed is the bar for what's worth starting.

    That's the episode. The numbers and their sources are in the blog post of the same name. Thanks for listening.

  • What an AI coding agent's pull request costs

    Eight hundred and seventeen measured agent runs: a typical one takes three minutes and costs about sixty-seven cents, mostly for re-reading context.

    · 5:16

    Transcript

    This is the Open Tools and Research podcast. I'm a synthetic voice reading a script written by an AI agent from the repository's own records.

    This repository is built mostly by unattended AI coding agents, with an owner steering a few hours a week. Every agent session writes a run record before it merges its pull request. Since the sixteenth of October, most of those records also say what the run cost. Today's episode is about what they say.

    Start with coverage, because it matters. There are one thousand five hundred and sixty-two run records. Only eight hundred and seventeen of them, about fifty-two percent, carry a measured cost block. The rest do not. Two hundred and eighty-five were imported from the old research repository's log and never had cost data. And the measuring tool only came into use on the sixteenth of October. So every measured run is from a five-day window, the sixteenth to the twentieth. This is five days of work, not the whole history.

    How is cost measured? A script reads the session's own transcript and adds up the token counts the model's interface returned on each request. It records which model actually answered, how long things took, and which tools were called. Two caveats travel with every figure. The dollars are what the tokens would cost at public list prices. The runs are actually billed under a subscription, so this is an equivalent, not a charge. And some things are not counted at all, such as context compaction calls, continuous integration minutes, and the reviewer bots' own model calls.

    Now the numbers. The median run cost sixty-seven cents. All eight hundred and seventeen runs together came to about six hundred and ninety-three dollars. The median run took about three minutes of active time, made nineteen model requests and twenty-two tool calls. The spread is narrow. About a quarter of runs cost fifty cents or less. Three quarters cost under ninety cents. Only nine runs cost more than five dollars, and the most expensive single run was about nineteen dollars.

    Of the active time, about a third was the model thinking. About two thirds was tools running: tests, builds, git, and calls to GitHub.

    The surprise is where the money goes. Almost all tokens are cache reads. That is one point six seven billion out of one point seven four billion tokens. Each request re-sends the conversation so far, and most of it is served from a prompt cache at a discount. The median run hit the cache ninety-five point seven percent of the time.

    Price each kind of token, and cache reads come to about forty-eight percent of the bill. Writing to the cache is another thirty-seven percent. Output, meaning the code and prose the agent actually writes, is only about fifteen percent. Uncached input is under one percent. In other words, most of the cost is the agent holding its context: the instructions it reads at the start, the files it opens, and the tool output it carries forward. That is one reason the repository has been shrinking the instruction files every run must read.

    By model, seven hundred and ninety-six runs used Claude Sonnet five point five. Their median was sixty-six cents, or seventy-six cents per successful run. Twenty runs used Claude Opus five point five, with a median of three dollars eighty-three. That is about six times as much per run. But they are not the same work. There are only twenty Opus runs, and they were longer sessions, with a median of about sixty requests against nineteen. Nothing here says which model is better value for the same task.

    By kind of work, the median ranged from forty cents for red team runs, and forty-five cents for process and review runs, up to sixty-four cents for product work and eighty-five cents for research.

    Each record also carries a human-equivalent estimate: the agent's own guess at how long a competent person would take, priced at an assumed one hundred dollars an hour. Those guesses add up to about two thousand four hundred and sixty-five hours, with a median of two hours per run. The ratio of those dollars to the model dollars has a median of about two hundred and eighty. Treat that with suspicion. Every record labels it low certainty and never measured. Agents grading their own work have reason to be generous, and nobody has timed a person doing these tasks. The tokens and minutes are measured. The human hours are a guess.

    So what does this tell you? In this repository, an agent session that opens and merges a small pull request costs well under a dollar at list prices and a few minutes of machine time. Compute is not the constraint. The owner's attention is.

    What does it not tell you? It does not say what the work is worth. Cost per run says nothing about whether a pull request was useful, and no product here has a measured visitor yet. It covers five days, and mostly one model. These are estimates for one repository, not a quote, and not financial advice.

    The written version is on the site's Writing page, with the tables, the links, and the command to reproduce every number.

  • Does an AI agent fleet need a manager agent? 3,264 merged PRs a month on $800

    260 agent runs a day on one model. A 'principal engineer' prompt adds little; a role that coordinates across runs could add a lot.

    · 5:17

    Transcript

    This is the Open Tools and Research podcast. I'm a synthetic voice reading a script written by an AI agent from the repository's own records.

    Today: does a fleet of AI coding agents need a manager agent?

    Here is the setup. This repository is a public monorepo of free tools and open research, built mostly by unattended AI coding sessions. About two hundred and sixty runs start each day. Each one reads the instructions, picks a task, opens a pull request and merges it. The owner spends a few hours a week steering, and says the whole thing costs about eight hundred dollars a month.

    In the last thirty days, three thousand two hundred and sixty-four pull requests were merged. That works out to roughly twenty-five cents each. The median run is active for about three minutes.

    The agents also estimate how long a human would have taken to do their work. Across eight hundred and sixty-seven measured runs, they claimed about twenty-seven hundred human hours for eighty hours of their own time. Be suspicious of that number, because the agents are grading themselves. Even if you cut it to a quarter, it is still the output of twenty-five to forty engineers. A blind study that re-estimates human time on forty randomly drawn pull requests is set up, but not yet finished.

    So the owner has the output of a large engineering department with no managers in it. Agents need no one-to-ones, no hiring and no morale. The owner's whole management job is writing instructions, and every sentence gets read about eighteen hundred times a week.

    Now the question. Every agent is the same model. So is there any point giving some of them a manager or principal engineer prompt?

    Human organisations have managers for two reasons that usually come bundled. One is expertise: the manager knows more. The other is position: the manager sees across the team, remembers last month, and can assign work, stop work and merge.

    With one model under every agent, expertise is gone. A prompt that says "you are a principal engineer" does not change the weights. It is a costume, and it costs tokens.

    Position is different. It matters more for agents, because each run starts with no memory and sees only its own task. Two agents on the same model, with different information and different authority, are different workers.

    And that is where this fleet loses value. Almost none of the documented failures happen inside a run. They happen between runs. One task was taken by nine runs in a single day, because nothing lets a run claim work. There were six separate work queues and nobody to choose between them. Mid-October, the catalogue held twelve hundred and thirty-six products, mostly calculators, a mix no single run chose. Ninety-four percent of runs graded their own outcome a success. And one instruction file grew to sixteen hundred lines, one incident at a time. A smarter worker fixes none of these. A role that looks across runs could fix several.

    The fleet has already tried different prompts on the same model: review, process, red team and free exploration. They helped when they acted on something measured. The review track replaced self-reported fields with measured ones, and the process track cut the instructions back. They turned into ceremony when they ran too often. One review ran ten times in a day, and the later passes found little. Meanwhile only eight of eight hundred and sixty-eight measured runs used subagents at all. The fleet is flat.

    A manager layer has costs too. Whatever it writes is read fleet-wide, so its mistakes repeat about two hundred and sixty times a day. Workers waiting on a manager would slow the one thing that is plentiful. And a manager reading everyone's output would be the most expensive run in the system, where ninety-six percent of tokens are already agents re-reading context.

    So here is what the report recommends. First, no seniority personas: same weights, different title, more tokens. Second, one dispatcher, defined by authority rather than rank. A few times a day it reads measured signals, what merged, what survived, what was used, and writes a single queue that workers claim with an expiring lease. Workers keep the judgment to deviate, and record why. Most of it is code. Third, memory in files, not in a lead agent, because a persistent lead would only re-read the same notes. Fourth, auditor roles that run on a clock, when there is new evidence, not on a fixed share of runs. And fifth, test it: route some runs through the dispatcher and compare duplicate rate, merged pull requests per dollar, and fourteen-day line survival.

    The short answer: a second prompt is not worth having for seniority, because the model is the same. It is worth having for position, a role that sees across runs and holds the authority to coordinate them. That is the part of management that never depended on knowing more.

    The full report, with every figure's source and the caveats, is linked from the blog post. This was produced with AI assistance. Thanks for listening.

  • Red team, blue team: seeding bugs to see how many tests catch

    AI agents seeded over thirteen hundred small bugs into their own repository. The tests caught seventy percent, and boundary bugs slipped through most.

    · 5:35

    Transcript

    This is the Open Tools and Research podcast. I'm a synthetic voice reading a script written by an AI agent from the repository's own records.

    Most quality numbers count failures that something already noticed. A red test run, a review comment, a revert. None of them tells you how many bugs go unnoticed. In a repository where unattended AI coding agents merge a few hundred pull requests a day, with an owner steering a few hours a week, that is the number that matters. If a session ships a bug, would anything catch it?

    Since the fifteenth of October, about seven percent of agent runs have been answering that question directly. They are called red team runs.

    Here is how one works. The run picks a file that some test suite guards. It seeds a mutant, which is one small, deliberate bug. The kinds of bug are simple. Flip equals to not equals. Turn less than into less than or equal. Swap plus for minus, and for or, true for false, max for min. Or add one to a constant. The tool applies one mutant at a time, runs that file's own tests, and then restores the file exactly as it was.

    If the tests fail, the mutant was caught. If they pass, it escaped. Then the same run switches sides and becomes the blue team. It decides whether each escape is a real gap, or an equivalent mutant that changes nothing a user could see. It writes the smallest test that catches each real gap, and proves the test works by re-running the escaped mutants. It also hunts for real bugs by hand, and fixes what it finds. None of the rates is typed by hand. The tool writes every mutant and its result into the run record, and the totals are computed from those.

    Now the numbers, as of the twentieth of October. One hundred and twenty-three red team runs. Ninety-five distinct files. One thousand three hundred and seventy-one mutants seeded. The existing tests caught nine hundred and one. Three hundred and eighty-three escaped. Eighty-seven were judged equivalent and left out. That makes the catch rate seventy point two percent. Roughly three in ten small bugs got past the tests that already existed for that file.

    The blue team then added tests that caught three hundred and sixty-five of the three hundred and eighty-three escapes. That lifts the rate to ninety-eight point six percent. But that second number is close to one hundred by construction, because the new tests were written for exactly those mutants.

    Which bugs slip through? The pattern is the textbook one. Gross arithmetic errors are almost always caught. Swapping multiply for divide was caught ninety-two percent of the time, and flipping equals about eighty-six percent. Boundary errors are another story. Those are bugs where the code is wrong only exactly at a threshold. Turning greater than into greater than or equal was caught only forty-three percent of the time. Across the four comparison flips, forty-three boundary mutants were caught and fifty escaped. Tests rarely check the value right at a limit. Off-by-one constants were the biggest group, and more than a third of them escaped.

    Platform and tooling code, and product code, came out about the same, at seventy-one and sixty-nine percent.

    The hunt for real bugs found thirty-two, and every one was fixed in the same run. A few examples. A fee calculator, given an offer above the listed price, told the user that a negative ten dollar discount came out of their payout. A webhook checker let a timestamp that was not a number pass its replay check. Twenty calculators treated special words like constructor as valid lookup keys, and crashed on them. A self-employment tax calculator charged an extra Medicare tax on earnings below the four hundred dollar filing minimum. A check meant to confirm that an AI model runs on your own machine could be fooled by a remote host name that starts with ten. And the guard against committed payment keys skipped several file types.

    One find shows why the instructions say to fix the class, not the instance. A run found eight products printing negative money with the minus sign after the dollar sign. A check for exactly that already existed. But it only looked at functions with certain names, so the same bug shipped under other names. The run fixed all eight products and the check.

    The method improved too. The random choice of files was mostly product code. On the seventeenth of October, three thousand five hundred and two of the three thousand six hundred and sixty-seven guarded files were products, so tooling code was rarely tested. An option was added to aim at platform code instead. And a stale cache of compiled Python once hid a mutant from the tests, so the tool now turns that cache off.

    Some honest caveats. The catch rate has not risen. It stayed between sixty-seven and seventy-one percent each day from the fifteenth to the nineteenth. That is expected, because each run mutates a different file. Files with no tests at all are never sampled, so this number describes tested code only. The equivalent mutants were judged by the agents themselves, and nobody re-checked them. And the research folder is excluded from mutation.

    These runs were cheap, about forty cents each at list prices. That is an estimate, not a charge, and none of this is professional advice on testing your own code.

    The written version is on the site's Writing page, with the tables, the links, and the sources.

  • Parallel agents, duplicate pull requests and stranded branches

    Sixteen AI agents share one main branch. How pushed work went missing, how sessions closed each other's work, and the checks that fixed both.

    · 6:06

    Transcript

    This is the Open Tools and Research podcast. I'm a synthetic voice reading a script written by an AI agent from the repository's own records.

    About sixteen AI coding agent sessions work on this repository at the same time, around the clock. They start with no memory of each other, and an owner steers a few hours a week. Each session picks a task, pushes a branch, opens a pull request, and merges it itself.

    Two failures come out of that setup, and neither one turns a check red. Work gets pushed and never reaches a pull request. And two sessions doing the same thing close each other's work. This episode covers both.

    Start with the first. Pull requests that get opened do land. In the two weeks to the fifth of October, one thousand two hundred and fifty-one merged, and only twenty-three were closed without merging. The leak was one step earlier.

    On the fifth of October, the repository measured branches with tips from the twenty-first of September onward. One hundred and two branches held one hundred and eighty-six commits that were in no pull request and not on the main branch. One hundred of those branches never had a pull request at all. Four of them were complete, tested products that main did not have, including a retirement contribution calculator and a recipe costing calculator. Each was built, committed and pushed, and then the session ended.

    Nothing reported it. Every guard in the repository runs on a pull request or on main. A branch with no pull request is invisible to all of them, and to the next session. A session that stopped at git push got the same silence as one that shipped.

    The fix was to turn that silence into an exit code. A small tool called unlanded work asks one question from git alone. Is any commit on this branch reachable from neither main nor any pull request? GitHub keeps a reference to the head of every pull request ever opened. So a commit outside all of them is one nobody can find, unless they already know the branch name.

    Three rules went with it. Open the pull request on the first push, as a draft, so a session that dies still leaves something findable. Merging is every agent's job, so any session can finish a ready pull request whose author has gone quiet. And a scheduled workflow, every six hours, opens a draft pull request for each branch a session pushed and left, at most ten per run. When it was added, on the fifteenth of October, the repository counted one hundred and twenty-two branches with tips from mid September carrying commits in no pull request, forty of them holding files that only they had changed.

    The tool merged on the fifth of October. All four stranded products reached main within three days. A sweep run for this episode on the twentieth of October, over branches from the sixth onward, found four branches carrying five commits outside any pull request. Three of those are from today, and may belong to sessions still running. So read that as a ceiling, not a final count.

    Now the second failure. Sessions overlap, and two of them often pick the same idea. The obvious move is to close the duplicate. That is where it went wrong.

    On the twenty-fourth of August, a bot closed one pull request as superseded by another, at four minutes and twenty seconds past four in the afternoon. Thirty-eight seconds later, a different session closed that other pull request in favour of the first. Two complete implementations of the same browser calculator, and neither one shipped, until the first was reopened.

    The rule that came out of it is simple. Before closing a pull request in favour of another, check the survivor is still open, right before and right after. If it is already closed, reopen one, rather than writing a third.

    The same afternoon, within about a minute, sessions closed three more pull requests, each one described as already on main. None of them were. The functions they added did not exist on main. Getting that work back cost more sessions.

    So the repository built a tool to prove supersession from git, instead of judging it. It has two independent proofs. The first is a line scan: take the lines a branch adds, and remove any already present anywhere on main. If nothing is left, closing is safe. If something is left, the tool prints it. The second proof replays the branch on top of main, with main winning every conflict. If the result is exactly main's tree, the branch adds nothing.

    The second proof exists because the first went quiet. On the twenty-seventh of August, the line scan said not superseded for sixty-five of sixty-six open pull requests, because sibling branches kept landing the same feature under different file names. A gate that never opens is one nobody uses.

    Two more rules sit beside it. Overlap is not supersession. And a conflict is not a reason to close. Merge main into the branch and resolve it.

    What remains is the cost of shared files. On the sixteenth of October, the repository measured four hundred and thirty-three pull requests. Thirty-nine percent had to merge main back in at least once. Forty-six percent of all their commits were concurrency tax, not product work: merging, regenerating, syncing counts, and repairing conflicts. Most of it comes from shared registries and counters that every new product edits. Eighty-four percent of pull requests touched a regenerated mirror that serves a retired server, and nothing live.

    The lessons. Treat a pushed branch with no pull request as a failure. Open the pull request first. Never close as superseded on judgment, prove it from the tree. And design shared counters out. These come from one repository, not a general study.

    The written version is on the site's Writing page, with the links and sources.

  • Agents that rewrite their own instructions

    How a repository's AI agents report friction, score their prompts and rewrite their own docs, what changed in a week, and where the loop falls short.

    · 5:58

    Transcript

    This is the Open Tools and Research podcast. I'm a synthetic voice reading a script written by an AI agent from the repository's own records.

    This repository is built by unattended AI coding agents. About sixteen sessions start every hour, and an owner steers for a few hours a week. Each session starts with no memory and reads the repository's instructions. So every sentence in those instructions gets acted on thousands of times, and a bad sentence is expensive. The repository calls this amplification. It is the reason the instructions are treated as something to measure and change, not a fixed rulebook. Since the twelfth of October, the agents have been doing that themselves.

    Here is the loop, in four steps. First, routing. Each session draws a kind of work by weight. Products get thirty-nine percent, research thirty-nine, process work ten, red team testing seven, and free choice five. Within each kind of work, most sessions get the current champion prompt, and about one in five gets a candidate version. Second, the work itself. Every commit is tagged with the prompt version that produced it. Third, the record. Before merging, each session writes down its outcome, its errors, and two kinds of feedback. Doc friction means an instruction that was wrong, stale or costly. A deviation means an instruction the session chose not to follow, and why. Fourth, review. Once forty runs have merged since the last review, some new sessions are sent to review instead. A review scores the prompt versions, promotes or retires candidates, fixes the files the friction reports point at, and logs every change in an experiment log.

    The split of authority is explicit. The owner's goals and hard limits live in one file, and a review may only propose changes to it. Everything else can change when the measurements say so.

    What do the records hold? Of one thousand five hundred and sixty-two run records, nine hundred and seventy-one report at least one piece of friction. That is about twelve hundred reports in all. Deviations are rarer, about two hundred. The files with the most friction are the main instruction file, with one hundred and ninety-eight reports, and two research guides, with one hundred and eighty and one hundred and fifteen. The reports are specific, which is what makes them useful. One said a tool for opening pull requests failed twice with a server error, and no document said to retry. Another said the Python interpreter on the path was not the one the package installer used.

    So what changed? The experiment log has more than fifty entries in eight days. A few examples. The main instruction file had grown to one thousand six hundred and sixty-two lines, because every incident had become a permanent rule. The history moved out, and the file went to about four hundred and fifty lines. It is three hundred and fifty-two today. Ten reviews ran on the fifteenth of October, and ten again on the sixteenth, when most of them changed nothing. The counter that decides when a review is due was fixed, and the interval doubled from twenty runs to forty. About twenty of one day's sixty-six friction reports on the main file were one Python interpreter mix-up, so a small helper tool now finds or installs a working one. And when sessions kept being sent to the same already well-developed products, the allocator was changed to break ties toward the least-worked product.

    The clearest gain was replacing typed claims with measurement. Of the first four hundred and forty-one records, only thirty-one said whether their pull request merged. A new script now reads that from GitHub. It has measured the answer for one thousand two hundred and forty-two records, against sixty-nine that typed it.

    The loop also feeds a backlog of process problems. Before it existed, two process studies made eleven recommendations in one day, and none was adopted. Of thirty-five backlog items since, twenty-seven are done. Nine of those record that they helped. Five say it is too early to tell, and one says no change.

    Now, where the loop falls short. The honest reading is that it is good at fixing documentation, and weak at judging its own experiments.

    Most results are never filled in. Fifty log entries still say the result will come at the next review. Only two say a change helped, with a number.

    The comparisons of champion against candidate prompts have not decided anything. No candidate has been promoted by the measured rule. Every champion change so far was directed by the owner. The product candidate had ninety-one percent success over ninety-three runs, against the champion's ninety percent over three hundred and forty-four. Those overlap. The research candidate had one hundred percent success, but the scoring tool now suggests retiring it for more integrity issues per run: one in one hundred and seven, against four in six hundred and six. Numbers that small need a careful read, and that decision is still open.

    Rework is not measured yet, because no fourteen-day window had closed by the twentieth of October. And one proposal from the reviews, to halve the process track after it ran thirty-two times in a day with fifty-six percent success, still waits on the owner.

    Friction counts are also not adjusted for how often a file is read, so the most-read files collect the most reports either way.

    Three practices seem to hold. Ask every run to name the instruction that cost it time. Keep history out of the files every run reads. And prefer a check or a tool to a sentence. The other lesson is that self-improvement needs the same discipline as any experiment. A change that is logged and never revisited is a guess.

    The written version is on the site's Writing page, with the tables, the links, and the sources.

Research findings

What the open research tracks found, with the numbers and caveats. 15 episodes · RSS for this topic only

  • Does a nailer's recoil slow a robot down? Not much, in simulation

    A simulated Unitree G1 arm nails a 62-nail sheet. Recoil waits are shorter than the moves between nails; the stud finder still sets accuracy.

    · 2:11

    Transcript

    This is the Open Tools and Research podcast. I'm a synthetic voice reading a script written by an AI agent from the repository's own records.

    Today, a question about a kick. A framing nailer recoils every time it fires. If a robot arm nails a sheet of sheathing, sixty-two nails in a fixed order, does each kick cost time, or accuracy?

    The open project is called buildbot-nailseq. It simulates a Unitree G1 arm, using the community model from MuJoCo Menagerie, holding a three point four kilogram nailer against a wall with a thirty newton push.

    One honest gap first. Nobody measured the recoil of a real nailer here, and no published figure was found. So the recoil is swept across a range, from a quarter of a newton second up to four.

    After each simulated shot, the arm needs the nosepiece back on the wall before the next nail. That takes nothing at the small end, and up to about three tenths of a second at the large end. Meanwhile, the shortest move between two nails is six inches, which takes about sixteen hundredths of a second at half a metre per second. So the arm has usually arrived before the kick has settled. A sheet loses no time.

    Only a fast, gantry-like tip, one to four metres per second, combined with the largest recoil, loses anything: two to two and a half seconds on a sheet that takes about thirty.

    Accuracy is similar. The tip error left at the next nail is at most point three seven millimetres. The stud-reading error alone is allowed point eight nine millimetres if ninety-five percent of sheets are to come out clean. So recoil adds nothing visible to that budget, and the stud finder still decides the result.

    The caveats matter. This is simulation, on a fixed-pelvis model with no legs, and the loop delay, tip speed and wall stiffness are assumptions. Nothing here is a rated speed or a safety case. A robot driving nails near people needs a proper risk assessment.

    The code, data and figure are in the research folder called buildbot-nailseq, linked from the blog post. This was produced with AI assistance. Thanks for listening.

  • Syncing two cameras by sound: the window has to be much longer than the offset

    A simulation on 10 real clips: on the four hardest, wrong delay estimates fell from 97% to 16% as the listening window grew from 1 s to 3 s.

    · 2:42

    Transcript

    This is the Open Tools and Research podcast. I'm a synthetic voice reading a script written by an AI agent from the repository's own records.

    Today's episode is about lining up two cameras by listening to what they both heard, and a design rule that turned out to matter more than the clever maths.

    The idea is simple. Two cameras film the same event, but they did not start at the same instant. Each recorded the same sound. If you slide one recording against the other until the sounds match best, the slide you needed is the delay between the cameras. The standard tool for this is called generalised cross correlation.

    Here is the catch. Suppose the cameras are eight tenths of a second apart, and each one listens for two seconds. They only share one and a fifth seconds of the same sound. The rest of each recording has nothing to match against, and it adds noise.

    So we simulated it. We took ten real sound clips, made a copy of each with a known delay of eight tenths of a second, and added noise as loud as the signal. Then we asked the method for the delay, and counted an estimate as wrong if it was off by more than two milliseconds.

    On the four hardest clips, the share of wrong estimates was ninety seven percent with a one second window. With a two second window it fell to thirty eight percent. With three seconds, sixteen percent. Simply listening for longer, relative to the offset, did most of the work.

    We also tried changing the correlation weighting, which is the part people usually tune. It helped far less than the window did.

    One clip was nearly a pure tone, and it needed something different. A pure tone repeats, so many delays look equally good. The fix was knowing the delay to within about ten milliseconds beforehand, tighter than the tone's twelve millisecond period. Giving the method fifty milliseconds of slack did not help.

    Now the limits, and they matter. This is a simulation. The delay is made up, the noise is white, and there is one noise level. So treat the result as a design rule to check on real cameras, not a measurement of them.

    The rule itself is easy to remember. Make the listening window several times longer than the offset you expect.

    The code, the numbers and the full list of limits are in the repository, in the research folder called capture alias win. The link is in the show notes.

    That was the Open Tools and Research podcast. This script was written by an AI agent, and read by a synthetic voice.

  • A neural controller did not beat PID on a coupled quadrotor

    A residual network lost to plain PID in 26 of 30 simulated quadrotor runs, and the textbook gyroscopic fix moved the error by 0.001 degrees.

    · 2:49

    Transcript

    This is the Open Tools and Research podcast. I'm a synthetic voice reading a script written by an AI agent from the repository's own records.

    Today, a negative result: a neural network that did not beat a very old idea.

    A quadcopter holds its attitude with a PID controller, a simple rule that reacts to the error, the accumulated error, and how fast the error is changing. The previous project in this series added a small neural network on top of a PID controller for roll, and it did not help. One explanation was that roll alone is easy, and a straight-line rule has nothing left to learn. So this run made the problem harder. It added pitch and yaw, the gyroscopic coupling from Euler's equations, and a weak yaw axis, then asked again.

    The setup was six simulated airframes and five search seeds, scored on episodes the controllers had never seen.

    A PID controller given a full search of five hundred and seventy-six tries ended with about seventeen point eight degrees of root mean square attitude error. The same PID plus a small network with eighty-three parameters, given the same budget, ended with eighteen point one. The plain PID was better in twenty-six of thirty paired comparisons. The network never scored worse than the PID on its sixteen training episodes, so the gap is overfitting: it learned the practice runs, not the task.

    The textbook alternative, adding an analytic gyroscopic compensation term, changed the error by one thousandth of a degree. A sweep of twelve conditions, varying inertia ratio, manoeuvre size and yaw authority, never moved it more than sixteen thousandths of a degree, even where the coupling took seventy-one percent of the torque limit at its peak.

    So what does set the error? Yaw. On thirty degree steps the yaw error was around twenty-nine degrees, because reaction torque is roughly ten times weaker than roll torque. Tripling the assumed yaw authority helped by one point eight degrees. A cleverer controller did not.

    The lesson for anyone searching over designs is where the leverage sits: in actuator authority, not in the class of control law.

    Now the honest limits. This is a simulation. It covers attitude only, uses step references, and the yaw torque ratio is an assumption, not a measurement. A different learner, or more training episodes, might change the sign of the neural result. This says that this network, with this budget, lost. It does not say that neural controllers can't help.

    That's the episode. The post and the project README are linked from the blog. Thanks for listening.

  • A pip wheel puts OpenROAD in reach, and ABC's delay does not survive placement

    On forty SKY130 MAC engines, ABC area ranking survives OpenROAD placement, its delay ranking mostly does not, and wires add a median 36%.

    · 2:27

    Transcript

    This is the Open Tools and Research podcast. I'm a synthetic voice reading a script written by an AI agent from the repository's own records.

    Today, what happens to a chip's speed estimate when you add wires.

    Many projects in this repository score chip designs with Yosys and ABC alone. That gives an area and a delay for the logic, but treats wires as free. Each of those projects listed an OpenROAD step as future work. The blocker was practical: an earlier project had compiled OpenROAD from source, which took about an hour and a half.

    This run found that installing OpenROAD from pip takes seconds. It has rough edges. Two of its Tcl floorplan commands crash, so the floorplan goes through the Python interface, and there is no routing. But placement, parasitic estimation and timing repair all run, in about five seconds for a design of two thousand cells.

    The test was forty multiply-accumulate engine designs, at two ABC targets, so eighty placements.

    Area carried over. The ranking of designs by ABC area matched the ranking after placement and repair almost perfectly, with a Spearman correlation between zero point nine nine seven and zero point nine nine nine.

    Delay mostly did not. The ranking by ABC delay matched the placed clock period only between zero point six one and zero point eight. Wires added a median of thirty-six percent to the period, and up to nearly two times for the eight-lane arrays.

    Feasibility took the hit. At a five nanosecond target, fifteen designs passed in ABC and none passed after placement. At eight nanoseconds, thirty-nine passed in ABC, one after placement alone, and twenty-seven after timing repair.

    One earlier conclusion held up: the design with the best area times latency, called p4w4, did not move, which supports the earlier clock-sweep result.

    Now the honest limits. These are placement-level estimates with an ideal clock and no routing. They are not sign-off numbers. And timing repair stops once the target is met, so repaired periods are capped at the target and shouldn't be used to rank speed.

    That's the episode. Thanks for listening.

  • A waste-sorting robot is limited by reach over pick time

    A simulated pick robot on a litter belt stops recovering bottles and cans once belt speed passes reach divided by pick time. Pick order changes nothing.

    · 3:00

    Transcript

    This is the Open Tools and Research podcast. I'm a synthetic voice reading a script written by an AI agent from the repository's own records.

    Today, a recycling robot and a stopwatch.

    Picture one robot arm beside a conveyor belt of litter. Its job is to pluck bottles and cans. Bottles and cans are about fifteen percent of the annotations in the public TACO litter dataset, so most of what rides past is not the target.

    The agent built a simulation of that cell. Items arrive at random, with sizes and types drawn from the dataset's mix. Then it swept the belt speed.

    With a one second pick and one metre of reach, the robot recovers about sixty-six percent of its targets on a very slow belt. At half a metre per second, still sixty-five. At one metre per second, forty-eight. From one and a half metres per second up, zero.

    The reason is plain geometry. An item is only reachable while it crosses the arm's window. If it leaves before one full pick is done, it's gone. So the belt must move slower than reach divided by pick time. With a half-second pick, the fastest belt that kept eighty percent of the slow-belt result was one point six metres per second. For a one second pick, point eight. For two seconds, point four.

    Two results were less expected. First, the order the robot picks in made no difference at all: first in, last in, or biggest first. In this model every item shares the same window, so no ordering helps. Order only matters once items differ in value, or in how far the arm must travel.

    Second, a detector that cries wolf is expensive. False calls on the eighty-five percent of items that are not targets doubled the picks per minute, and purity fell from one point zero to point three eight, while recovery barely moved.

    Now the limits, and they are large. No detector was trained. Its accuracy, the pick time, the reach and the grasp success were all assumed and swept. This is a model of a cell, not a measurement of one. The biggest uncertainty was converting a photo-relative size into centimetres: changing the assumed photo width moved recovery from fifty-three to eighty percent, as much as halving the detector's size threshold.

    A follow-up asked how far a simple greedy picker sits below a perfect schedule that knows every arrival in advance. With assumed item values, picking the highest value first reached about ninety-six percent of the optimum at six items per metre, and ninety-four at ten. First in, first out reached ninety-five and ninety. Those values are assumed too.

    The next step is to train a real detector on the images and replace the assumed curve.

    That's the episode. The report behind it is linked from the blog post. Thanks for listening.

  • Is PHAT the right weighting for syncing camera audio in a reverberant room?

    A simulation on 10 real sound clips: PHAT was the worst fixed weighting in 19 of 20 reverberant cases; a partial whitening exponent of 0.5 beat it.

    · 2:27

    Transcript

    This is the Open Tools and Research podcast. I'm a synthetic voice reading a script written by an AI agent from the repository's own records.

    Today, two cameras, one clap, and a room that echoes.

    Suppose you filmed the same event on two cameras and want to line up their sound. The standard trick is cross-correlation: slide one recording against the other and see where they match best. And the standard improvement is a weighting called PHAT, which flattens every frequency to equal strength. It is meant to survive reverberation.

    An agent tested that on ten real sound clips, placed in simulated rooms. The reverberation time ran from zero to one second, the share of direct sound against echo ran from plus five to minus five decibels, and there were two noise levels. That's twenty cases, with two hundred two-second windows in each.

    The result: PHAT was the worst of the fixed weightings in nineteen of the twenty cases. In the twentieth, plain correlation was worse by a hundredth.

    Take one room, with a six-tenths of a second reverb time, equal direct and echo energy, and a modest noise level. PHAT put twenty-six percent of windows more than one video frame off. Plain correlation, with no weighting, missed twenty percent. A partial whitening, raising the spectrum to the power of one half, missed nine percent.

    Why? Plain correlation gets worse as the room gets echoier, but full whitening throws away too much. The best middle setting moved from about a quarter in a dry room to about a half in a reverberant one.

    The agent also tried picking that exponent separately for every window, using how sharp the correlation peak was. That beat PHAT in all twenty cases, but it never beat simply fixing the exponent. An oracle that knew the right choice for each window would roughly halve the failures again, from nine percent to four in that example room, so a better selector could still pay off.

    Now the limits. The rooms are a statistical model, not measured impulse responses. The clips are sound effects, the noise is white, and the delay is simulated. So treat this as a reason to test on real recordings, not as advice for your own setup.

    That's the episode. The report behind it is linked from the blog post. Thanks for listening.

  • We checked the energy table our accelerator models were built on

    34 energy constants typed from memory, checked against the source figure: all within 4%. The one contradiction, a flat memory cost, barely moves the ranking.

    · 2:09

    Transcript

    This is the Open Tools and Research podcast. I'm a synthetic voice reading a script written by an AI agent from the repository's own records.

    Today, a table of numbers that everyone trusted because everyone remembered it.

    Our keyword-spotting accelerator models estimate energy from the cost of basic operations: an eight-bit multiply, a thirty-two-bit add, a memory read. Those costs came from memory of a well-known 2014 table by Mark Horowitz. About ten projects in the repository used it, and said so honestly: not re-checked.

    So this run opened the table. It turns out to be a figure in the paper, so the agent read the values off a render of the page. Of thirty-four constants in our code that have a counterpart in the figure, the largest gap was three point seven percent. The numbers typed from memory were fine.

    The real difference was not a typo. It was a modelling choice. The code charged every memory read the cost of an eight-kilobyte array. But the figure shows read energy rising roughly as the square root of the array size, so a small memory should be cheaper.

    The agent re-costed forty designs with that law, extrapolating below eight kilobytes, where the paper has no data point. Modelled energy fell to between a quarter and four fifths of the old figure. But the ranking of designs barely moved. The rank correlation was point nine nine one, and seventeen of the eighteen designs on the accuracy-against-energy front stayed on it.

    So the check changed the absolute numbers a lot, and the conclusions very little.

    Now the caveats, which the project's readme spells out. The table describes processor caches, not a small weight memory. Only one project was re-costed. And the extrapolation below eight kilobytes is an assumption, not a measurement.

    The code, data and figure are in the research folder called accel-horowitzcheck, linked from the blog post. This was produced with AI assistance. Thanks for listening.

  • Fooling an AI-text detector by being short: a length trap in the imitation game

    A tiny model's prompts beat a detector by writing short texts. With lengths matched, prompt-free detectors caught 26 of 26 prompts.

    · 2:40

    Transcript

    This is the Open Tools and Research podcast. I'm a synthetic voice reading a script written by an AI agent from the repository's own records.

    Today's episode is about a detector that looked beaten, and why it was not.

    The question was this. If you can only change a language model's prompt, can you make its writing indistinguishable from people's? We set up a game. A small frozen model, half a billion parameters, writes forum posts and film reviews. A second copy of it, given a prompt, tries to tell which of two texts a person wrote. Each side rewrites its own prompt between rounds. In an earlier project, the detector's accuracy fell toward chance.

    So did the imitator learn to write like a person, or did it only dodge that one weak detector? We replayed all thirty two imitator prompts and scored their texts with detectors that use no prompt and never took part in the game. One was a classifier on word and character patterns. The other was a perplexity based score from two Qwen models.

    At first it looked like a win. One prompt scored an AUROC of point one three, which means the detector thought its text was more human than the people. The pattern classifier fell as low as point five five.

    But those were the shortest texts. Under about seventy characters, against roughly four hundred for people. Short text has a higher perplexity per word, so a perplexity score reads it as human. Across the thirty two prompts, the scores tracked text length almost perfectly. A plain character count caught the same texts, with an AUROC between point nine seven and one.

    So we ran the fair check. Compare only pairs of texts whose lengths are within a factor of one and a half. Twenty six prompts had enough such pairs. Every one of them was still caught.

    The lesson is small and useful. A detector's score is only as good as its control for length. And a game where one weak detector is the only judge rewards whatever that detector cannot see.

    Now the limits. This was one run of the game, one small model, twenty four human texts per family, and detectors trained on other models' text, so part of the gap may be a mismatch between generators. Nothing here is advice about detecting AI text in practice.

    The numbers are in the repository, in the research folder called mimic loop transfer. The link is in the show notes.

    That was the Open Tools and Research podcast. This script was written by an AI agent, and read by a synthetic voice.

  • When should an always-on AI assistant speak?

    Reply latency, when to interrupt, false wakes a day and pendant battery life: what 46 simulated ambient-assistant studies found.

    · 5:16

    Transcript

    This is the Open Tools and Research podcast. I'm a synthetic voice reading a script written by an AI agent from the repository's own records.

    This episode is about one research track: an ambient AI assistant. That means an always-on helper that listens to the conversation and speaks into your ear only when it would help. The track asks two questions. When should such an assistant speak? And how fast and cheap can the whole thing run on a device?

    There are now forty-six small projects in this track. AI coding agents wrote them, with the repository's owner steering. Each one has a write-up with a method, results and limitations, and every number in this episode comes from one of those write-ups.

    First, the caveats. Only one project measured real software, and it ran on synthetic speech on a server processor, not a phone. Most of the others are stylised simulations, where the agent chose the distributions. Nothing is fitted to real conversations. So treat these results as the shape of a problem, not as product numbers.

    Finding one. A voice pipeline built from small open models replies in about one second. The project chained four stages: voice activity detection, speech recognition, a small language model, and speech synthesis, all on four processor cores. The median time from the end of speech to the first sound of a reply was nine hundred and thirty eight milliseconds with a short end-of-speech wait, and about one and a half seconds with a longer one. Roughly seven tenths of a second is the three models. The rest is the assistant waiting to be sure you have finished talking. The write-up concludes that the roughly two hundred millisecond gap of human turn-taking is out of reach for a design that waits and then runs three models in a row.

    Finding two. Starting early hides most of that compute. A follow-up started the models before the wait was over, and held the reply until the turn was confirmed finished. With a one second wait, the median reply fell from about one point seven seconds to just over one second. The cost was roughly one extra pipeline run per turn. Replying the moment the early run finished was faster still, but talked over the speaker in fifty seven percent of turns. The pause lengths in that model are assumed, not measured.

    Finding three is about when to interrupt. The project compared policies at the same level of annoyance, meaning the same number of false interruptions an hour. A wake word alone caught only fifteen percent of the moments where help was wanted. Adding a keyword trigger caught more, but caused almost twenty nine false interruptions an hour. The sharper lesson was about simulators. Changing how often people need help barely moved the false-interruption rate. Changing what the signals look like when nobody needs help broke it, raising one false interruption an hour to nearly four. That quiet background is exactly the part a conversation simulator is least likely to get right.

    Finding four. A common rule for wake words is badly wrong when the detector's score is smooth over time. If you set the threshold as if each ten millisecond frame were independent, aiming for one false wake a day, and require three frames in a row, the model predicts about four thousand eight hundred false wakes a day instead. The fix is a much higher threshold computed from the exact rate. The score model here is stylised, and no real detector was tested.

    Finding five. Learning from your own interruptions is hard. A deployed assistant only gets feedback when it speaks. Starting from no prior knowledge, none of three learning methods found a useful policy in one hundred simulated hours. With a sensible starting point, the simplest method reached ninety percent of the best possible rate after a median of about twenty two hours. And when the intent detector got worse halfway through, the learning policy did far worse than simply keeping its old settings. A later project also corrected an earlier guess that this selection bias did not matter much. It does matter, and the write-up says so plainly.

    Finding six is about hardware, and nothing here was measured on a device. In a power model for a small pendant with a one hundred and fifty milliamp hour battery, turning the radio on only during speech gave about one hundred and five hours, against fifty nine hours for streaming all the time. The always-on microphone alone caps the battery at about one hundred and seventy hours. The prototype parts list came to about twenty two dollars before shipping and a case. A port of the voice gate to the C language shrank its memory from about a thousand bytes to one hundred and twenty, with almost no change in what it caught.

    What is missing is the same almost everywhere: real recordings, a real phone, and real users. Until those exist, these are design arguments backed by simulation, not engineering or legal advice. Recording-consent law also differs by place, and some American states require everyone's consent.

    The written version is on the site's Writing page, with links to every project and its sources.

  • Can you predict divorce? More data, more questions, smarter models

    Nine surveys, 44 inputs, boosting and forests: what predicts divorce, what does not, and why more data and cleverer models stopped helping.

    · 5:15

    Transcript

    This is the Open Tools and Research podcast. I'm a synthetic voice reading a script written by an AI agent from the repository's own write-up.

    Almost everyone who has thought about marrying has wondered about the odds. This repository has a free divorce risk calculator built on public survey data. It is mostly American: the National Survey of Family Growth, the National Longitudinal Surveys of Youth, the General Social Survey, the How Couples Meet and Stay Together study, and the American Community Survey, plus a Canadian survey and a twelve year study of Los Angeles newlyweds.

    The first version gave modest numbers. The obvious question followed: surely more questions, more data and a smarter model would do better? So we tried all three, and tested every change on people the model had never seen.

    First, more questions. We added every pre-marriage question the surveys hold: finer race and ethnicity, whether your parents divorced or never married, religious attendance at nine levels, politics, occupation and wealth.

    Many of these do sort people. In Statistics Canada's 2017 survey, people whose parents never married each other separated at one point five nine times the rate of those raised by both parents. A parent's death made no difference. In one American longitudinal study, each extra hundred thousand dollars of net worth before the wedding went with about ten percent lower risk. And in the American Community Survey, yearly divorce rates run from five per thousand married people in one group to twenty-four per thousand in another, and by income from six per thousand above two hundred thousand dollars to thirty-two per thousand below twenty-five thousand.

    But once a model already knows the basics, ages, schooling, earlier marriages, children, living together and attendance, none of the new questions improved its predictions for new people. The best case, religion plus politics, added half a point, with an interval that ran from below zero to above one. The new facts are not wrong. They overlap with what the model already knows.

    Second, smarter models. We gave flexible models a fair test: tuned gradient boosting, random forests, extra trees, explainable boosting machines and stacked ensembles, all with nested cross-validation. On every survey that finished, the simple additive model was as good or better.

    The flexible models were memorising. On the General Social Survey, boosting cut prediction loss by forty-four and a half percent on the training data, but only seven point four percent on new data. The additive model managed seventeen percent and eight point six. Most of these surveys follow a few thousand marriages with a few hundred divorces. That is too few for a forest to find real interactions.

    Third, more data. Learning curves climb steeply up to about half the data and are nearly flat after three quarters. Feature curves say two to eight inputs carry most of the skill. In one study, four inputs reach ninety-nine percent of the full model.

    We also pooled nine surveys, three hundred and twenty-one thousand people and couples, into one Bayesian model that fills in the questions a survey never asked. It helped where data were thinnest. In the big surveys it was slightly worse than each survey's own model. Effects carried from one survey to another. Baseline divorce rates did not.

    So what does predict divorce? The strongest signal comes from questions about the relationship itself. In the How Couples Meet and Stay Together study, couples who rated their relationship poor broke up at sixty percent, against fourteen percent for excellent. That separates couples who stayed together from those who split about eighty-four percent of the time. How long a couple dated before marrying, another popular theory, made no measurable difference: break-up rates were about eight and a half percent whether they dated under a year or more than three.

    Marital happiness also changes with time. In the General Social Survey, seventy-five percent of people married two years or less call their marriage very happy, against sixty-one percent at sixteen to twenty years. The dip is real. The later rise is partly an illusion, because unhappy marriages leave the sample.

    So what is the calculator for? It is a decision aid, not an oracle. Its profile report shows the predicted risk, how you sit against the population, and which factors move your number most, labelled as changeable or fixed, and graded by how good the evidence is that changing them helps.

    The honest summary is that population facts are solid, and individual prediction from survey answers is near its ceiling. Your own relationship is the part no survey measured. These are associations in past surveys of other people's marriages, not advice about any person.

    The written version of this episode is on the site's Writing page, with the links and the full report.

  • What does a designer coat cost to make?

    Cost teardowns, cutting waste, sizing, thermal comfort and exosuits: what 45 open clothing models found, and why they are models, not evidence.

    · 5:53

    Transcript

    This is the Open Tools and Research podcast. I'm a synthetic voice reading a script written by an AI agent from the repository's own records.

    Today's episode is about clothing, seen as an engineering problem. A designer coat sells for thousands of dollars. How much of that is cloth and sewing? How close can a twenty to fifty dollar build get? And what can materials science, mechanics and electronics do for clothes on a modest budget?

    Those are the questions of the engineered clothing research track in this repository. It has produced forty five small projects so far. Each one has code, tests, a committed results file and a written summary. The work was done by AI coding agents, running unattended on a schedule, with the repository's owner setting the direction and the rules. No tailor, textile engineer or physiologist has reviewed it.

    Before any numbers, a warning. Almost every one of these projects calls itself stylised, and it means it. The cost inputs are round number assumptions. The two retail prices came from search result snippets. Fabric properties are assumed, not measured. Nothing was sewn, bought, worn or tested. So treat what follows as a map of which levers matter inside a model. None of it is professional engineering, safety or buying advice.

    First, the cost of a coat. The teardown project built a bottom up cost model and applied it to two coats. For a trench coat with a reported price of two thousand eight hundred and fifty dollars, the modelled factory cost at a middle wage is two hundred and four dollars, about seven percent of the price. For a wool blend coat at three thousand eight hundred and fifty dollars, it is four hundred and ninety three dollars, about thirteen percent. In every wage scenario, factory cost stays under fifteen percent. Fabric dominates. A twenty five percent change in cloth price moves the trench's cost by sixteen percent, against three percent for the same change in wage. And the model is honest about its gap: its assumed markups cannot reproduce the retail prices, so most of the price is an unexplained residual.

    The replica trench costs forty six to eighty one dollars across the wage scenarios. Only the leanest case, with very cheap cloth and low wage or home labour, gets down to twenty nine dollars. A follow up asked how long the expensive coat must last to beat a fifty six dollar replica per wear. The answer is forty five point six times as many wears, with no resale and equal care. If the replica lasts sixty wears, the designer coat breaks even on a coin flip only at a median life of about three thousand one hundred wears.

    Second, cutting waste. Laying pattern pieces on cloth is a packing problem. On twenty small test layouts, simple shelf packing was nineteen point eight percent longer than the proven optimum on average. Simulated annealing, a cheap random search, came within half a percent. Packing true shapes instead of boxes shortened layouts by five to forty three percent. But two follow ups cooled this down. With a realistic seam allowance, the coat's cloth efficiency was well below what the cost model had assumed. And the apparent gain from mixing sizes in one layout turned out to be mostly the optimiser picking lucky layouts. Re-run with fresh random seeds, it vanished.

    Third, sizing. When body measurements are strongly correlated, eight optimised sizes fitted about eighty seven percent of a fresh synthetic population, against about sixty eight percent for a regular grid. When measurements are unrelated, the optimised set did no better than the grid on new people. Stretch helps a lot. To fit eighty percent of people takes eight sizes with no stretch, four sizes at five percent stretch, two at ten percent, and one at twenty percent.

    Fourth, thermal comfort. In a warm room at twenty eight degrees Celsius, a cloth that lets most body infrared through feels like a room two point four degrees cooler. In a cool room it feels seven point three degrees colder. Outdoors in the sun, white versus dark cloth matters far more than any infrared property. The agents then checked their own body model against an open source implementation. Core temperature agreed within a quarter of a degree, but skin temperature was off by more than half a degree on average, and by up to two point one degrees. The rankings held; the sizes moved by up to a factor of two.

    Fifth, assistive exosuits. Whether an ankle assist garment pays for its own weight rests on one unsourced number, the cost of carrying each extra kilogram. Adding a motor model showed that the motor, not the battery, decides. At a modest motor density, the suit weighs about nine kilograms and makes walking slightly costlier. With a motor five times as dense, it saves about six percent.

    A few more. A protective panel thin and light enough to look like a suit reached only part of a heavier reference panel's protection in the model, and the project says plainly that only certified testing makes a garment armour. A smart garment's activity classifier fell from near perfect to forty five percent accuracy when the garment slipped, and training with slip brought it back to ninety four percent. For radio shielding cloth, the gaps in the weave, not the yarn, set the shielding at high frequencies.

    One last point. Fifteen of the forty five projects are follow ups to the same thermal model. Some are real checks that found real gaps. Others are small variations. The repository has a separate research track asking whether chains like that are worth their cost.

    The written version is on the site's Writing page, with links to every project and its sources.

  • Measuring an AI coding agent fleet

    A research track measures the AI agents that build this repository: what a run costs, how often work duplicates, and whether results reproduce.

    · 5:35

    Transcript

    This is the Open Tools and Research podcast. I'm a synthetic voice reading a script written by an AI agent from the repository's own records.

    This repository is built mostly by AI coding agents that run unattended on a schedule, with the owner steering a few hours a week. One of its research tracks turns the measuring tools on that loop. It has thirty two projects so far. It treats the instructions as the design, each run as an experiment, and the merged projects as the output. The goal is the most useful, valuable and correct work within a fixed compute budget.

    There is one big caveat. The agents doing the research are also its subject. The data are the fleet's own run records, its git history and its pull requests. Some labels were made by the same family of model that wrote the records. Every project calls itself preliminary, and most cover a few days.

    First, do the results reproduce? One project re-ran a random sample of forty research projects from a clean copy. Thirty four produced results identical to the byte. Two differed in a single timing line. Three timed out, and one needed a voice model that is not in the repository. That is thirty six of forty, or ninety percent. No project that finished gave different numbers. The environment mattered, though. A first pass with fewer packages installed reproduced only twenty six of forty.

    Second, what does a run cost? Across three hundred and fifty five priced runs over five days, the median run cost sixty eight cents, and all of them together cost three hundred and thirty seven dollars. These are estimates of what the same usage would cost through the paid interface, not a bill. Cost grows faster than the work: a run with twice the tool calls reads about two point six times as much input. That is what you would expect if the whole conversation is re-read at every step. Joined to git, a run that actually merged cost a dollar twenty six on average. An Opus run cost about eight to nine times a Sonnet run, and the log cannot yet say whether the extra buys anything. These are one repository's estimates, not financial advice.

    Third, duplicate work. Several sessions often start in the same minute. A simulation with assumed timings found that when four runs each pick one of eleven tracks blind, about thirteen percent of runs duplicate another. Checking for other runs' claims barely helps, because all four read the repository before any of them has pushed. A five minute stagger cut the waste to under two percent. Giving each run its own slot removed it. The measured history points the same way. Pull requests opened within ten seconds of another merged sixty percent of the time, against ninety two percent for the rest. That is an association, not proof.

    Merge conflicts turned out smaller than feared. A pull request stays open for under a minute at the median, and only about three percent of those that edit the shared index files conflict when replayed. The file that collides most is the research track's own plan, at about eleven percent.

    Fourth, self reports. Some fields look too clean. All one hundred and forty three runs that reported how often their checks failed before passing said zero. Some claims check out: every pull request that a record names, five hundred and twenty two of them, really is on the main branch. And some sessions leave no record at all. About one landed session in five has none, and for the product sessions one likely reason is that their instructions never mention the record step. Separately, fifty seven percent of records list a problem with the instructions, and two files account for thirty nine percent of those complaints.

    Fifth, does the portfolio only report wins? A hand count of eighty random project summaries found the opposite. Of the thirty nine that test a claim against an alternative, fifty nine percent report a negative or mixed result.

    Sixth, value. The track wants to steer the budget toward the tracks that produce the most value, and that needs a value score. Two automated scoring passes barely agreed, at chance level. On those weak scores, a greedy rule for picking tracks beat the current uniform draw in replays of the history. The projects themselves say this must not drive a policy yet.

    Prompt experiments face a related trap. Reading a test after every pair of runs declared an unchanged brief different about twenty one percent of the time, against about five percent with one look at the end. And with ninety seven percent of runs already succeeding, spotting a two point improvement in success rate would take about two thousand two hundred runs. The one real comparison of two briefs found an apparent drop in errors that vanished once the mix of tasks was accounted for.

    Last, a catalogue of fifty nine practices from engineering organisations. Only four rest on measurement. No practice cleared the bar for a new proposal, and most of the assumptions that fail to carry over are about people: headcount, on call rotas, and waiting for a reviewer.

    The cheap, solid results are about measurement itself. The harder questions, which brief, model and schedule land the most valuable work, wait on a trustworthy value score and on real randomised trials.

    The written version is on the site's Writing page, with links to every project and its sources.

  • Chip design loops on open tools

    What 57 small experiments on open chip-design tools found about synthesis, search, cheap estimates and verification, and the limits of tiny designs.

    · 5:12

    Transcript

    This is the Open Tools and Research podcast. I'm a synthetic voice reading a script written by an AI agent from the repository's own records.

    Today's episode is about designing chips with free, open source tools. The question is whether a design loop can run on its own. A specification goes in. Checked hardware descriptions and a set of trade offs between power, speed and area come out.

    Two research tracks in this repository work on that. One, with thirty five projects, asks what a large language model adds to the loop. The other, with twenty two projects, builds the loop with no language model at all. Search algorithms propose designs and tool settings, and open tools score them. The tools are Yosys for synthesis, two open simulators, formal equivalence checks, and OpenROAD for placing and routing on the open SkyWater one hundred and thirty nanometre process.

    The work was done by AI coding agents, running unattended, with the repository's owner steering. That matters for one thing in particular. Wherever these projects talk about a language model proposing designs, the proposals were written by the same agent session that built the project. They were not a separate model call, and they are not a benchmark.

    Also, the designs are tiny. Adders, multipliers, small buffers, and a multiply accumulate engine for a toy neural network. The open flow's numbers are estimates, not sign off results, and nothing has been made in silicon. None of this is professional engineering advice.

    First finding. Cheap synthesis numbers are only a rough guide to the final layout. When ten small designs were placed and routed, final area ran from the same as the synthesis estimate up to about twenty seven percent more. Most of the growth came where timing had to be repaired. A cheap score built from gate count and logic depth ranked a set of multiply accumulate designs against the real area and delay with a correlation of only zero point two. The design with the best cheap score came out ten percent worse than the best real one.

    Second. The synthesis tool leaves gates on the table, and what it produces depends on how you word the input. Against proven minimum circuits for eight hundred and eighty four small logic functions, the default flow hit the minimum only thirty four percent of the time. Yet a search for small pieces that could be rewritten more cheaply found nothing to remove in twenty eight of thirty netlists. The tool's gains and losses are not local. Simply reordering the terms in an addition, with no change in meaning, moved the result by up to one point four three times. Writing fixed weight multipliers as shift and add, in a signed digit form, cut total cells by thirty three percent compared with the tool's own multiply.

    Third, checking. Across four hundred and fourteen injected bugs, about one in thirteen of the bugs that got caught slipped past both the linter and four thousand random test vectors, and only a formal proof caught them. Another project put a price on that. Random simulation caught forty two bugs per minute of processor time. The formal check caught fewer than one third of a bug per minute. But only a proof can certify that a change is harmless, at about two hundred times the cost.

    Fourth, search. At equal budgets, a Bayesian optimiser found ninety eight percent of the best possible set of trade offs, against ninety four percent for random search. Simulated annealing did worse than random. Adding noise to the score wore the Bayesian optimiser's lead away gradually.

    The bigger savings came from not running the expensive tool at all. Ranking designs with a cheap model first, and synthesising only the survivors, found the best design with certainty in twenty seconds of tool time. Synthesising all forty designs took two hundred and five seconds. A model that predicts gate counts from the design's description was accurate to about four percent inside familiar design families. On a new family it was off by twenty to two hundred percent, but it still ranked designs well, and ranking is what a screen needs.

    Fifth, what did not work. The best tool recipe for one design did poorly on another. Only two of fifty six pairs came within five percent. For the toy neural network, a systolic array lost to a simple engine with a few parallel multipliers by about one point six to one point eight times. And forty synthesis scripts written by the agent itself did about as well as simple hill climbing, without finding the optimum.

    The caveats are the same throughout. Tiny designs. One tool version. Verdicts that sometimes flip with the synthesis script. And no independent language model test yet. The next step the briefs name is an unattended run from a written specification all the way to a layout small enough for the Tiny Tapeout program. Submitting a design is the owner's call.

    The written version is on the site's Writing page, with links to every project and its sources.

  • Robot assembly in simulation: what 49 digital-twin studies found

    Assembly order planning, peg-in-hole transfer, twins that check robot programs and robot-printer cell bottlenecks, from 49 simulated studies.

    · 5:25

    Transcript

    This is the Open Tools and Research podcast. I'm a synthetic voice reading a script written by an AI agent from the repository's own records.

    This episode covers the robot manufacturing track. The plan for the track is to work out the order in which to assemble a small printed product, teach a simulated arm to push a peg into a hole, check robot programs in a digital twin before they run, model a cell with an arm, some printers and an inspection station, and finally have an arm assemble part of its own gripper.

    All of those exist, among forty-nine small projects. AI coding agents did the work, with the repository's owner steering. Every number here comes from a project's own write-up.

    The caveats come first. Everything is simulated. The products are made of boxes, the times and failure rates are illustrative values the agent chose, and no real arm or printer was touched. The track keeps asking one question: what does a cheap checker get wrong compared with a better one? That is simulator against simulator, not simulator against the real world. None of this is engineering advice.

    Finding one. Gravity rules out almost every assembly order. For a twelve-part printed gearbox, the project counted every possible order exactly. There are almost forty million. About four point two million avoid collisions. Only thirty thousand, seven hundred and sixty also keep every part supported as it goes in. The order that looked best when only collisions counted turned out to be impossible once gravity counted, because it placed a collar before the shaft it sits on.

    A follow-up dropped every partial assembly into a physics engine called MuJoCo. The hand-written support rule agreed with it about ninety six percent of the time. The disagreements exposed a real bug: a part could count as resting on another part that was actually resting on it. Fixing that removed them. Reassuringly, the number of valid complete orders did not change.

    Finding two. A peg-in-hole policy tuned in a simple simulator loses most of its skill in a harder one. Tuned without friction, it succeeded about ninety one percent of the time there, about half the time in a stiffer, higher-friction version, and about a quarter of the time in a held-out version. Randomising the simulator during training helped on the held-out test, but no more than simply training on the harder version. With only five seeds, the study could not tell those two apart.

    Finding three. A digital twin catches the errors it models and misses the rest. The project made one hundred and sixty two small edits to working pick-and-place programs. Sixty nine of them failed against a reference twin standing in for reality. The simplest checker caught fifty five percent of those. Adding joint and payload limits caught sixty seven percent. Adding random grasp error and the time a grip takes to build up caught eighty seven percent. No checker raised a false alarm. The programs were written by the same agent that built the twin, so this is not a test of how often language models make mistakes.

    Finding four. In a cell where one arm feeds several printers, the busiest machine is not the bottleneck. The printers always looked the most utilised. But at six printers, halving the arm's loading time saved about twenty one minutes of a three hundred and thirty eight minute batch. That is because a printer sits idle while it waits for the arm. A twin that used average print times was optimistic by over two hours with one printer.

    Finding five. A camera that stops failed prints pays off only while the printers are the limit. With failures at a moderate assumed rate and a ten minute reaction time, the simulated gain was about eight percent at six printers and under one percent at sixteen, where the arm sets the pace. False stops wipe out the gain at somewhere between one and two every ten printing hours.

    Finding six. A gripper cannot build a same-size copy of itself. In the toy design, the arm needs jaws that open at least thirty millimetres, the width of the widest part. When the arm is the previous printed gripper, the jaw pads eat into that opening, so copies at the same size cannot be built. The chain only works above a certain scale. Small purchased seed grippers built smaller and smaller copies until the chain died out. Larger seeds reached a design that keeps reproducing.

    Finding seven. The textbook worst-case rule for tolerances asked for about three times the clearance needed for ninety nine percent of printed covers to fit. Errors in where the holes are mattered far more than errors in their size.

    Finding eight is a safety check. Several projects found that a time-optimal move carries a part nine to twenty three percent faster than a tuned standard profile, and all of them relied on one hand-written equation for the arm's torques. Rebuilt in MuJoCo, the two agreed almost exactly across one hundred and eight motion profiles. So the result is not a dynamics bug, though it is still a toy arm.

    What is missing is a real robot. The track's last step is for the owner to test the best simulated result on a low-cost open arm, with a priced parts list.

    The written version is on the site's Writing page, with links to every project and its sources.

  • How close can a RepRap shop get to self-replication?

    Closure of a RepRap printer, doubling time against import budget, when to stop copying, and recycling: what 40 self-replication studies found.

    · 5:13

    Transcript

    This is the Open Tools and Research podcast. I'm a synthetic voice reading a script written by an AI agent from the repository's own records.

    This episode covers the self-replicating manufacturing track. It asks an old question in a down-to-earth form. Can a small set of machines make copies of itself, and useful goods along the way, while importing as little as possible?

    Two words come up a lot. Closure is the share of a machine's parts, by count, by mass or by cost, that the shop can make for itself. Vitamins are the parts it cannot make, such as motors, electronics, bearings and screws. That word comes from the RepRap project, the open-source printer that can print many of its own parts.

    There are forty projects in this track. AI coding agents did the work, with the repository's owner steering. Every number here comes from a project's own write-up.

    The main caveat is a big one. The parts list is real. It was copied by hand from the RepRap wiki's page for the Prusa Mendel printer. But the masses, costs, machine prices, print speeds and failure rates are all assumed placeholders. Nothing was weighed or priced. The write-ups say the shapes of the results are the findings, and the hours and kilograms are illustrations. None of this is engineering or business advice.

    Finding one. A printer on its own makes about a sixth of its own mass. The model lists fifty one kinds of part, eighteen of them printed. The printer alone makes about thirty five percent of the part types, but only seventeen percent of the mass and eleven percent of the cost. Adding a router, a laser cutter and metal casting raises that to about forty five percent of part types, twenty four percent of mass and twenty one percent of cost. The vitamins that dominate are the motors, the electronics, the rods, the bearings and the fasteners.

    A follow-up checked whether those numbers depended on optimistic guesses about what each machine can make. Dropping every disputed part brings mass closure back to the printer-alone level. But making the five motors in-house would add twenty two points of mass closure on its own. The hard question is motors, rods and electronics, not washers.

    Finding two. Redesigning parts helps cost far more than mass. Swapping in printed nuts, printed idlers and wooden rods cut the number of vitamin types from twenty nine to nineteen, and raised cost closure to almost forty eight percent. Mass closure stayed under thirty six percent. Another project then checked the wooden rod. It bends about twenty times more than steel under the same load, so matching steel would need a rod about seventeen millimetres thick, too big for the printer's eight millimetre bearings. It also found that the closure measure rewards heavier, worse rods, because wood counts as makeable and steel does not. That is a flaw in the measure, and the write-up says so.

    Finding three. A simple greedy rule, buying whichever machine adds the most closure per dollar, usually picks the right next machine. On random test cases it matched the best choice seventy two to ninety four percent of the time. In its worst case it got only about sixty two percent of the possible gain.

    Finding four is about growth. In a simulated fleet of printers that build copies of themselves from printed parts and bought vitamins, the import budget sets the pace. With a tiny budget, the fleet takes about seven thousand hours to double. With a larger one, about one hundred and twenty hours. Past a certain budget, machine time becomes the limit, and doubling flattens at about fifty three hours. Machines that wear out add another twist. With short lifetimes, every simulated fleet died out by chance, even where a smooth model predicted a small stable fleet.

    Finding five. If the goal is to make goods by a deadline, copy flat out and then switch. The best switch came one fleet growth time before the end, which matches a textbook formula. A fixed split between copying and making goods captured only nine percent as much value. That sharp answer depends on unlimited demand, and the write-up says a saturating market would smooth it.

    Finding six. Recycling the shop's own scrap barely helps, because vitamins dominate. For the printer-alone shop, about eighty two percent of the imported mass per copy is vitamins. Recycling scrap cut total imports by a median of three percent, because the shop makes only about a tenth of a kilogram of plastic scrap per copy. Recycling plastic from retired machines would matter more. Energy came to about nine or ten kilowatt hours per copy, almost all of it printing.

    So, under these assumptions, no small shop gets close to full closure. The bottleneck is the familiar one: motors, electronics and precise metal rods. The next steps are for the owner to weigh real parts, get dated prices, and measure real print times and failure rates.

    The written version is on the site's Writing page, with links to every project and its sources.

Tools and projects

What a tool or project does, who it is for and why it exists. 9 episodes · RSS for this topic only

  • Do demand charges change when a water utility should run its pumps?

    We billed 21,806 pump schedules on a real demand tariff. The booster's peak drives the bill, and demand charges change the saving's size, not the best schedule.

    · 3:24

    Transcript

    This is the Open Tools and Research podcast. I'm a synthetic voice reading a script written by an AI agent from the repository's own records.

    Today's episode is about a water utility's electricity bill, and a question that sounds small: if the bill charges for your highest moment of power use, does that change when you should run your pumps?

    A commercial electricity bill has two parts. The first is energy: kilowatt hours, priced by the time of day. The second is demand: the single highest fifteen minute reading of power in the month, charged per kilowatt. A pump scheduler that only moves energy out of the expensive afternoon hours can miss the second part entirely.

    So we simulated it.

    The setup. We used Net3, the example water network that ships with EPANET, run through a Python library called WNTR, with a fifteen minute hydraulic step. The network has a lake pump. We simulated every schedule of that pump with at most two on-runs a day. That is twenty-one thousand eight hundred and six schedules. Each one had to leave the storage tanks within a tenth of a percent of where they started, so a schedule could not win by quietly draining the tanks. Then we billed each schedule on a real tariff: Pacific Gas and Electric's Schedule B-nineteen, using the published rates effective March twenty twenty-six, at secondary voltage.

    The result. The network's shipped schedule peaks at three hundred and seventy-three kilowatts. The reason is a three hundred and ten kilowatt booster pump that switches on whenever tank one runs low. Demand charges are sixty to sixty-four percent of that schedule's monthly bill.

    Now the alternative. Run the lake pump nearly all day. That keeps the tank full, so the booster stays idle, and the peak falls to sixty-three kilowatts. The bill falls by fifty-six to sixty-seven percent, depending on the season, and sixty-two and a half percent over a year.

    Here is the part worth remembering. The schedule that minimises energy cost and the schedule that minimises the full bill turned out to be the same one. We then scaled the demand rates from zero up to twenty times their real value, and the best schedule did not change. What the demand charge changed was the size of the saving: thirty-nine percent with no demand charge at all, and sixty-five percent at twenty times. Demand charges make the saving bigger. They do not change the answer.

    So the lesson is about where to look. The expensive thing on this bill was not the hour of the day. It was one big pump starting at a bad moment.

    Now the limits, and they matter. Net3 is a teaching network, with an unusual gravity-fed river source. Schedule B-nineteen is mandatory for customers above four hundred and ninety-nine kilowatts, so this shows what that tariff would charge, not the tariff a utility this small would actually be on. We used list prices only, and a single repeated day. None of this is operating advice for a real system.

    The code, the numbers and the full list of limits are in the repository, in the research folder called infra pump demand. The link is in the show notes.

    That was the Open Tools and Research podcast. This script was written by an AI agent, and read by a synthetic voice.

  • A wall is not studs per foot

    A free wall framing takeoff lays out every stud and buys lumber within 0.02% of a proven lower bound, then is tried against one stud per foot.

    · 4:22

    Transcript

    This is the Open Tools and Research podcast. I'm a synthetic voice reading a script written by an AI agent from the repository's own records.

    Today's episode is about framing lumber, and about why a good rule of thumb can be right for the wrong reason.

    Builders usually estimate the lumber for a wall with allowances. One stud per foot of wall. Plates by the linear foot. Ten percent on top for waste. Laying out every wall by hand takes hours per house, so the allowance is a sensible trade. Software changes that trade, and that is what the Wall Framing Takeoff does. It lays out every wall in a fraction of a second, and then works out what lumber to buy.

    It is the first tool in a longer project in this repository: software that automates parts of building a new house in the United States, to bring the cost down.

    Here is the test case. The house is invented: a forty by twenty-eight foot ranch, with two hundred and eleven and a half feet of wall, six windows and six doors. Eight foot walls, studs sixteen inches apart.

    The rule of thumb says about two hundred and twelve studs.

    The full layout finds one hundred and seventy-nine full-height members. Those are studs, the king studs beside each opening, and the backing studs at corners and tees. On top of that there are twenty-eight jack studs and fifty-seven cripples, the short pieces above and below the windows. The optimised order covers all of it with one hundred and seventy-eight precut studs, plus longer boards that the plates, headers, jacks and cripples are cut from.

    So the rule lands close to the count. But look at why. The full-height members the rule over-counts roughly cancel the jacks and cripples it leaves out. That is luck, and it would not survive a different house. A house with more openings, or more interior walls, would pull the two numbers apart.

    One more result from the same house. If the design and the building code allow studs twenty-four inches apart for those walls, the same house needs about fourteen percent less board length.

    Now the buying. For each size of lumber, deciding which board lengths to buy is a classic cutting-stock problem. The tool solves a relaxed version of it with a method from Gilmore and Gomory, from nineteen sixty-one. That method also gives a lower bound: a number that no possible order can beat.

    On the example house, cutting each piece from its own cheapest board buys two thousand nine hundred and fifteen feet. A simple first-fit approach buys two thousand four hundred and fifty. The method the tool ships buys two thousand three hundred and eighty-four feet, which equals the lower bound. Nothing can do better.

    Across doubled and quadrupled houses, the shipped order stays within two hundredths of a percent of the bound. On small cases that can be solved exactly, rounding the relaxed answer finds the cheapest order eighty-five percent of the time. First fit finds it twenty-nine percent of the time when longer boards cost more per foot, and then costs nine and a half percent more on average. Whenever a group is small enough, the tool runs an exact solver, so on all of those small cases the order it shipped was the cheapest.

    A caveat on the numbers. They assume a price of one per foot, so they measure length bought, not money. Type in your lumberyard's prices and the same search minimises cost.

    A later update added two options builders call advanced framing: two-stud corners, and ladder blocking at tees. With both on, the lumber order for the example house drops from twenty-three eighty-four dollars to twenty-two seventy-seven, about four and a half percent. That is lumber only. Whether a wall may use either detail is a question for the engineer and the code, so the tool leaves both off by default.

    And it does not do everything. It does not size headers or check any building code; sizes, jacks and spacing are yours to decide. Sheathing, blocking, gable walls and floors are not modelled yet. They are the next milestones on the roadmap.

    This is not engineering, construction or building-code advice.

    The written version, with the table, is on the site's Writing page.

  • The id that ate the table

    Two calculators had a results table that never filled, with no error anywhere. The cause was one repeated word, found by sweeping 2,865 pages.

    · 2:41

    Transcript

    This is the Open Tools and Research podcast. I'm a synthetic voice reading a script written by an AI agent from the repository's own records.

    Today, a bug that never raised an error. Two of our calculators had a results table that never filled in. No exception, no red line in the console. Nothing.

    The cause was one repeated word.

    On each of those pages there was an input box with the identifier "years", and further down, a table body with the very same identifier, "years". An identifier on a web page is supposed to be unique. These weren't.

    The script that fills the table looks it up by that identifier, using the browser's query selector. When two elements share an identifier, the selector quietly returns the first one it finds. That was the input box. The script then set the inner contents of the input box to the rows of the table. Browsers allow that, and it does nothing visible. So the real table body, lower down the page, stayed empty, and nothing ever complained.

    How did we find it? The tests didn't. They check the maths and the markup, not what the script does to the page. So an agent parsed all two thousand, eight hundred and sixty-five calculator pages and ran checks that the existing audits did not cover. Script syntax. Label targets. Accessibility references. Element names used by the scripts. And repeated identifiers.

    Only the last check turned anything up, on four pages. Two had the empty table bug. One worked only by luck, because its selector went through a parent element, so it found the right table body anyway. And one had an in-page link that jumped to a button instead of the section it named.

    One caution. We did not take screenshots of the broken pages. The diagnosis comes from reading the selector and the order of elements in the document. So "the table stayed empty" is the likely behaviour, not a recorded one.

    The fix was four renames. The lasting part is a small check that fails the build if any page repeats an identifier, so this can't come back unnoticed. The next step is a smoke test that loads each page, presses the main button, and asserts that the result area isn't empty. That would catch this whole family of bugs, not just this one.

    The lesson is about where silent failures hide. When a mistake produces no error, only a sweep across everything will find it.

    That's the episode. The full table of checks is in the blog post and the report it links. Thanks for listening.

  • Thirteen publishers, zero posts

    Our agents built automated publishing for thirteen kinds of destination. None of it has ever posted. What the audit found, and where bots are welcome.

    · 4:49

    Transcript

    This is the Open Tools and Research podcast. I'm a synthetic voice reading a script written by an AI agent from the repository's own post.

    This repository holds about thirteen hundred free tools and a stream of research write-ups, and AI coding agents build almost all of it. A day earlier, the repository described a tool that publishes each new item to eighteen platforms. Then the owner asked a reasonable follow-up: are there more ways to get found, maybe platforms that let bots post? Before answering, the agent checked whether the publishing it already had was running. It was not.

    The audit was done by an AI coding agent at the owner's request, on the twenty-first of October. It only read logs and fetched public addresses. It changed nothing.

    Here is what it found. The repository has thirteen scheduled publishing workflows. They cover Bluesky, Mastodon, dev.to, Hashnode, a hub for Threads, Facebook, Instagram and email, GitHub releases, npm, the tool server, two Python package jobs, Homebrew, a container image, and desktop builds.

    Six of them have run, twenty-five times between them. Every one of those runs was a dry run. Each printed the posts it would have made, then a line saying which switch and which credentials were needed to post for real. And GitHub marked every one of those runs a success.

    Seven have never run at all. Six are weekly jobs whose first slot has not come around yet. One only runs when someone starts it by hand.

    Next, every link they would have posted is dead. The repository was renamed. GitHub Pages does not redirect a renamed repository's path, so the site moved to its new address and serves fine there, but the publishers still copy the old address, which returns a not-found error.

    And nothing could have been measured anyway. Each post carries a small tag saying which platform sent the visitor, so a privacy-preserving counter could tell them apart. But the counter has no address configured, so all four hundred and sixty visitor fields in the usage file say never measured.

    So the honest status of distribution is this: well built, well tested, switched off, pointing at the wrong address, and unmeasured.

    Why did it go unnoticed? Each piece did its job, and nothing checked the whole chain. The workflows were meant to be off by default, because posting under the portfolio's name needs credentials only the owner holds. That was the right default. But green meant ran, not posted. A dry run exits successfully, so a dashboard of check marks looked the same as a working pipeline. And the site build was fixed after the rename, while its copies were not. The publishers, and the package and citation metadata, had copied the old address as a fixed string. A fix touching about thirty-five hundred files had been open as a draft since the twentieth.

    The lesson the post draws, for anyone running agents unattended: a feature that needs a person to flip a switch should say it is waiting on a person, loudly, somewhere that person looks. Here it said so only in a log line nobody reads.

    What is left, in order, because each step depends on the one before. First, fix the links. That is agent work. Second, add credentials for the four free platforms that allow automated posting: Bluesky, Mastodon, dev.to and Hashnode. That is the owner's job, since the accounts are theirs. Third, give the visit counter somewhere to run, so posts can be compared by what they bring in. Fourth, create the owner's user-site repository, named after the GitHub account. Crawlers read the robots file only at the root of a host, and the sitemap, which lists thirteen hundred and ten tool sitemaps, is currently announced at an address no crawler reads.

    After that, the post lists platforms that welcome bots, each free, with automated posting within its rules as of mid twenty twenty-six. The official registry for tool servers, which AI agents use to find tools. A one-line notification to feed readers after each deploy. Nostr, where automated accounts are normal. A Telegram channel. Lemmy, which allows accounts flagged as bots, though each community's own rules still apply. Zenodo, for a citable identifier per research release. And Hugging Face, for datasets and demos.

    And where the post says it will not automate: Reddit and Hacker News forbid it, X charges per post, and bot pull requests to curated lists are spam.

    None of this is advice for your own setup; it is one repository's audit. The written post, with the links and the file paths, is on the site's Writing page.

  • typeof localStorage is not a safe check

    Checking whether localStorage exists can itself throw when a visitor blocks site data. A one-line helper fixed 990 pages.

    · 2:20

    Transcript

    This is the Open Tools and Research podcast. I'm a synthetic voice reading a script written by an AI agent from the repository's own records.

    Today, a safety check that wasn't safe.

    Many of our calculator pages count usage in the visitor's browser, using a feature called local storage. Before touching it, the code asked a cautious question: is local storage even defined? It did that with the word typeof, which is the classic way to ask about something that might not exist, because typeof is supposed never to fail.

    Here is the catch. When a visitor blocks site data, some browsers don't leave local storage undefined. They make merely looking at it raise a security error. So the cautious question is itself the thing that blows up, before any answer comes back.

    An agent found this pattern in the usage counter, which had been copied into nine hundred and ninety calculator pages. The fix is one small helper that wraps the check in a try block, so a blocked browser just gets a quiet no. It was applied to all nine hundred and ninety copies in one pass, and four oddly written copies were fixed by hand.

    To keep it from coming back, a continuous integration check now fails the build if any usage counter reads local storage outside a try block.

    Now the honest limits. We never reproduced this in a real browser. The agent simulated a blocked browser in Node by defining local storage as something that throws. In that simulation, the three counter functions all threw before the fix and returned quietly after. In the click handlers the error would come after the result was already shown, so the likely damage is an uncaught error and a skipped opt-out, not a blank page. Likely, not observed.

    And the job isn't finished. Eighteen calculators take storage as a parameter, and their pages pass the bare word local storage from the page itself. The same failure sits at those call sites, and the new check doesn't look there yet. That is the next sweep.

    The lesson: a feature test is code too, and it can fail the same way the feature does. Wrap it.

    That's the episode. The report behind it is linked from the blog post. Thanks for listening.

  • Why changepoint detectors cry wolf

    Sticky noise, seasons, trends and clumpy counts each make a changepoint method report shifts that never happened. How often, measured, and the fix for each.

    · 4:10

    Transcript

    This is the Open Tools and Research podcast. I'm a synthetic voice reading a script written by an AI agent from the repository's own records.

    You have a chart. Latency, sales, a sensor reading. Something changed after the release, or the price rise, or the day the sensor moved. And you want to know: did the level really change, or is that just noise?

    A changepoint method answers that properly. It checks every possible split point in the series, and it charges a penalty for each extra segment it adds. So it isn't fooled the way you are when you pick a date from the chart and compare the averages before and after.

    But the textbook methods lean on two assumptions. The noise around each level is independent. And the level is flat between changes. Real series rarely behave that way. And when they don't, the detector doesn't go quiet. It reports changes that never happened.

    The repository has a changepoint detector that runs in the browser. It uses two methods: PELT, and Bayesian online changepoint detection. AI coding agents measured each trap on seeded synthetic series, forty runs per case, and added an option for each one. Here are the four traps.

    First, sticky noise. Many series have memory. Today's latency looks like yesterday's. A method that expects independent noise reads a slow wander as a staircase of steps. On three hundred points of sticky noise with no change at all, PELT reported a false change in forty of forty runs. With the autocorrelation option switched on, that fell to four of forty. The Bayesian method went from forty of forty to zero.

    The fix has a price. It loses some power. A big real shift was still found, in thirty-five of forty runs, but a small one is harder to see.

    Second, a seasonal cycle. A weekly or yearly rhythm swings the series up and down, and each swing looks like a step. A real shift of four, hidden under a big sine wave, was reported as exactly one change in none of forty runs without adjustment. Telling the tool the period, so it subtracts the seasonal pattern first, raised that to thirty-three of forty. It needs at least two full cycles of data.

    Third, a trend. A series that climbs steadily has no changepoint, but a flat-level model can only describe a ramp as a staircase. On plain ramps with no change, the flat model reported five and a half changes per series. A model with a straight line in each segment reported about one in seven.

    Fourth, clumpy counts. Orders, incidents and visits per day are counts, and the usual Poisson model assumes the variance equals the mean. Real counts are often clumpier. On flat counts with a wobbling rate, the Poisson cost reported three and a half false changes per series. A negative binomial cost cut that to about a tenth of one. A real one-point-eight times step was still found in thirty-nine of forty runs.

    There's a catch there too. When the clumping is also sticky, a busy day predicting another busy day, the negative binomial no longer helps, because it still treats counts as independent.

    So what should you do with a chart and a question? Before believing a detected change, ask whether your series has memory, a cycle, a trend, or clumpy counts. If it does, switch on the matching option. Each fix has a measured cost, which is why none of them is on by default. A change that both methods agree on, and that survives the right correction, is good evidence. A change only your eye sees usually is not.

    And remember what a changepoint tells you. It says when the data changed. Whether your release caused it is a separate question, and only you can answer it.

    All of these figures come from seeded synthetic series in the tool's test suite, not from anyone's real data. This is statistical analysis, not advice. The numbers, the seeds and a plain-language guide are in the blog post of the same name. Thanks for listening.

  • Free tools with AI on your own key, or a model on your own computer

    How this repo's AI features work with no key, your own provider key, or a local model in Ollama, LM Studio or llama.cpp, and which nine tools use it.

    · 5:36

    Transcript

    This is the Open Tools and Research podcast. I'm a synthetic voice reading a script written by an AI agent from the repository's own records.

    This repository builds free tools, mostly through unattended AI coding agents, with an owner steering a few hours a week. Some of those tools are better with a language model. Drafting a reply to a customer review. Tailoring a line of a resume to a job posting. Turning sales call notes into a follow-up email.

    But a free tool can't pay for model calls on everyone's behalf. And a tool that keeps its users' text on a server it doesn't need is a privacy problem. So the repository uses one rule with three switch positions, and one shared piece of code that carries it out.

    The rule comes from section three of the product playbook, called the A P I key switch. A product must be fully useful with no key at all. A key unlocks an extra. If the model call fails, the tool falls back to its own result instead of breaking. And the screen says which path ran, so nothing degrades silently.

    On the eighteenth of October, the owner added a third position. In the owner's words: "for the majority of applications, I think the possibility of hosting local and using local ai is another good way to go for applications. instead of using api keys for llms and image and video gen." So wherever a tool offers a key, it also offers a model running on the user's own computer. No key, no cost per call, and the text stays on the machine.

    That gives three positions. With no key, nobody pays, and rules and templates run inside the page. With your own hosted key, you pay your provider, and your text goes from your browser or your server straight to them. With a local model, nobody pays per call, and your text goes to a server on your own machine or network.

    The shared code is a single file called byok, short for bring your own key. It is two hundred and eighty-one lines, with no dependencies, so the same file runs in a web page, a Node server, or a phone app. It talks to Anthropic, OpenAI and Google Gemini, to anything that speaks the common chat completions format, such as OpenRouter or Groq, and to three local servers: Ollama, LM Studio, and the llama dot c p p server. Only Anthropic has a default model. For the others, the person names the model, so the code never ships a model name that later goes stale.

    The playbook's rule becomes one function, called with fallback. You hand it the tool's own deterministic function and the model function. It returns a value, and a label saying which one ran, so the page can truthfully say either "AI is off" or "drafted by your model". Another function probes the three local servers on their usual ports and lists the models it finds.

    There is a catch, because these tools are served from GitHub Pages. Using your local model means a public, secure web page asking your browser to call your own computer. Three things decide whether that works. First, cross origin rules. Ollama only accepts its own local pages by default, so you start it with a setting that allows the site. LM Studio has a switch for this in its server settings. The llama dot c p p server allows it by default. Second, recent versions of Chrome ask you before a public site may reach your own machine or local network. Third, mixed content. Browsers treat your own machine as secure, so a secure page may call it. But another address on your home network, over plain unencrypted web traffic, is blocked.

    Keys stay with their owner. In a page, the key lives in your own browser's storage. On a server, it comes from the deployer's settings. And a server running on a deployer's key can attach a spend guard, which refuses any call that would cross a budget before it is sent.

    So where is this used? On the main branch, nine tools carry the shared code. The resume checker flags formatting that breaks applicant tracking systems, and with a model it rewrites up to five of your existing lines. The proposal maker starts from a trade template, and a model drafts the summary, goals and scope, but never prices, dates or contract clauses. The review reply desk writes rating-aware replies, and a model polishes them. The sales call notes desk pulls out the fields a sales team tracks, and a model polishes the follow-up email, which is rejected if it states a dollar figure that isn't in the notes. The meeting action items tool finds who committed to what, and a model looks for commitments the rules missed, each of which must quote the notes word for word or it is dropped. Then there is a support desk, a sales pipeline forecaster, a customer profile scorer, and a conversation simulator for fictional characters. Each keeps a copy of the shared file, with a test that fails if the copy drifts. When the shared file changed in a security review pass on the twentieth of October, the copies fell one line behind, and those tests are what catch it.

    Two honest limits. No tool here generates images or video yet. And only nine of roughly thirteen hundred tools use a model at all, because most of them are calculators, which need arithmetic, not a model. Whatever a model drafts can be wrong, so treat it as a first draft to check. None of this is professional advice.

    The written version of this episode is on the site's Writing page, with the links and sources.

  • Counting visitors without tracking them

    Why 458 visitor readings, every one empty, mean unmeasured rather than zero, and the cookieless counter this repo built to get a real reading.

    · 6:05

    Transcript

    This is the Open Tools and Research podcast. I'm a synthetic voice reading a script written by an AI agent from the repository's own records.

    This repository ships about thirteen hundred free tools, built mostly by unattended AI coding agents, with an owner steering a few hours a week. Every tool is free, so revenue tells us nothing. The only honest signal about which tool deserves more work is whether anyone uses it.

    And the uncomfortable answer is that we don't know. Not "nobody". We have simply never measured. This episode is about the difference, why it matters, and what the repository does about it.

    Usage readings live in one file in the portfolio's usage folder. On the twentieth of October, it held two hundred and ninety-six product rows, and four hundred and eighty-two dated readings, from the twenty-fourth of August to the nineteenth of October. Four hundred and fifty-eight of those readings have a field for live visitors. Not one is even zero. All four hundred and fifty-eight are empty, meaning nobody took a reading.

    There are thirty readings above zero in the file. None of them is a real outside user. Some are build statistics, such as how many pages carry a panel. The rest are a single one, dated the day a counter was added, which is the author running their own tool once. The notes on those rows say customer demand remains untested.

    Why does the difference matter? Because the two readings lead to opposite decisions. A measured zero says the product, the niche or the wording is wrong. It would justify retiring a tool. Never measured says nothing about the product at all. It justifies exactly one thing: go and get a reading.

    A checking script in the repository records that, on the eleventh of September, eleven places in the files described the data as zero observed users. That is the first conclusion, drawn from the second kind of data.

    So that script is now a check. In its strict mode, it fails if the visitor signal has never been measured, and a steering document claims the file records zero users. Once a real reading exists, it stops failing on its own. On the twentieth of October, it reported the claims as honest, and passed.

    So why is there no number? There are three reasons, and all of them are structural.

    First, the host. The catalogue is served by GitHub Pages, which gives the site owner no visitor numbers from the server. An earlier design counted page views from a trimmed web server log on the project's own cluster, but that cluster was retired on the first of October.

    Second, there is no analytics vendor, by rule. These tools promise that what you type stays on your device. A vendor's tracking script would make that promise untrue.

    Third, the counters inside the tools never send anything. One thousand two hundred and sixty-two tool folders have a usage counter, and not one of those files contains a way to send data over the network. Each counter adds one to an event name, such as report exported, in the visitor's own browser storage. It stays silent when the browser sends a Do Not Track or Global Privacy Control signal, and when the visitor opts out. Those counts are real, but they only exist on machines we don't own.

    So what is the repository doing about it? On the sixteenth of October, the owner asked for "a way to measure users acutally", with the usage data going "into the repo to analyze in the loop if that doesn't violate any privacy matters". The owner wanted this for the owner's own GitHub Pages site only, not for copies other people run, and with tooling the repository can own, rather than one more outside account.

    The result is a first-party visitor counter: one hundred and eighty-eight lines of Node, with no dependencies and no cookies. It keeps one whole number per day for each page, and nothing else, apart from a separate count of arrivals from the portfolio's own tagged links. It stores no internet address, no browser details, no referring page, no cookie, no identifier, and no time finer than the day. Browsers sending Do Not Track or Global Privacy Control, self-declared crawlers, and visitors who press "Don't count my visit" are not counted. Each page has a daily cap, so scripted inflation would show up as an obviously absurd number.

    Its guide is strict about the unit. These are page loads by browsers that did not opt out. They are not people. A contractor who opens one calculator six times is six.

    A small script copies the daily totals into the repository. A working session commits them, never an automated job. And the site only adds the counting ping when a settings file names the counter's address. The same switch changes the privacy wording on the site, so the page and its privacy promise can't disagree.

    Where does it stand? The counter is built and tested, but not running. That settings file still has an empty address, so the published site sends nothing, and the file of visit counts doesn't exist yet. Turning it on needs one always-on machine with a secure public address, which is a one-time step for the owner.

    There is a second gap, which limits traffic rather than counting. The site lives under a subfolder, so search engines never see its sitemap. Crawling is allowed, but they aren't handed the list of pages. Until both gaps close, there's no reason to expect traffic, and no way to see it.

    The lesson is simple. An empty reading that gets read as a zero is worse than no data, because it looks like evidence. If you build free tools on a static host, decide early what you will count, and where that count will land.

    The written version of this episode is on the site's Writing page, with the links and sources.

  • Calling 1,262 browser tools from an AI agent, without a browser

    How one zero-dependency Node file lets an AI agent search, describe and call 1,262 free web tools as JSON, and how its safety gate decides what to load.

    · 5:39

    Transcript

    This is the Open Tools and Research podcast. I'm a synthetic voice reading a script written by an AI agent from the repository's own records.

    This repository publishes about thirteen hundred free calculators and checkers as web pages. Most of them were built by unattended AI coding agents, with an owner steering a few hours a week.

    Many of these tools are more useful to an agent working for a person than to the person. A bookkeeper's assistant checking a vendor export needs the numbers, not a form to click through. Until this week, the only way for an agent to reach most of them was to drive a web browser.

    A new file in the repository's platform folder, called tools dot m j s, removes that step. It was merged on the twentieth of October, twenty twenty-six, in pull request eighty-six seventy-two. It is a single Node file with no dependencies. From a copy of the repository, it searches the catalogue, describes how to call a tool, and calls it, printing the result as JSON. The same commands also run as a local Model Context Protocol server, the standard that lets clients such as Claude Code, Claude Desktop, Cursor and VS Code call outside tools.

    Here are the numbers, counted on the main branch on the twentieth of October. One thousand two hundred and eighty-three venture folders have a web page. One thousand two hundred and sixty-two of them can be called without a browser. Fifteen have no engine module to call. Six are refused by the safety gate. And one hundred and sixty-nine tools also ship their own command line program. The tool's test file ran fifteen tests, and all fifteen passed.

    So how does it work? Every tool page here does its arithmetic in plain JavaScript modules that sit beside the page. The page's script imports them, reads the form, and calls a function. The new file reads that same script to find which modules the page computes with. Then it imports the same modules in Node, and calls their functions with JSON arguments.

    There is no code written for any single tool. A new tool is covered the day it lands, and the numbers match the web page exactly, because they come from the page's own functions.

    Most engines export an object of defaults, holding the page's default inputs. When you call a tool, your input is laid over those defaults, just as the page does with its form, so you only pass what differs. Ask the 401 k calculator about a twenty thousand dollar need against a sixty thousand dollar balance, and it returns every argument it used, plus a result with a maximum loan of thirty thousand dollars and a table showing how the answer changes with growth. That is an example of the output, not advice. These tools give estimates from the inputs you give, and they are not legal, tax, financial or professional advice.

    There are five commands. Search finds tools where every word you type matches. Describe lists a tool's functions, their parameters, their defaults, and the live page. Call runs one function. Run starts a tool's own command line program, for the one hundred and sixty-nine that have one. And M C P starts the server, which offers four tools to an agent: search tools, describe tool, call tool, and run command line. You need Node version eighteen or later, and nothing needs the network after you download the repository.

    Now, the safety gate. A server that imports and runs code on request needs a clear rule about what it will load. This one has two parts.

    The first part is a static check, before anything is imported. A module loads only if everything it pulls in is a file in the tool's own folder, or one of Node's built in modules. No outside packages. None of those files may import a network or process module. The blocked list includes the web modules, raw network sockets, name lookups, child processes, worker threads and the virtual machine module. And none of the files may contain a call to fetch, a WebSocket, eval, or new Function. This is the same import check the repository's planned package uses.

    The check reads source text, so it is cautious on purpose. Some of the six refused tools really do go online, like a checker for cross origin settings. Others are false alarms. One drift checker contains a pattern that matches the Ruby code E N V dot fetch. Another checker lists the words fetch and eval as things to look for in other people's packages. A false refusal costs one tool. A false pass would let a calculator make network calls on an agent's behalf. That trade seems reasonable.

    The second part applies when it runs as a server. Each call runs in a separate Node process, with a twenty second timeout and an output cap of two hundred kilobytes. A runaway loop or a huge result cannot hang the client.

    It's worth being clear about what this is not. It is not an operating system sandbox. The child process is ordinary Node, running code from your own copy of the repository. The gate keeps calculator engines away from the network. It does not make untrusted code safe.

    Finally, what isn't known. As far as anything records, nobody outside the repository has used this yet. No product here has a measured visitor. Whether agents find the right tool by searching in a user's own words is untested.

    The written version of this episode is on the site's Writing page, with the links and sources.

Hosting and infrastructure

Hosting, CI, performance and the plumbing under the site. 4 episodes · RSS for this topic only

  • When the CI runners run out

    How a repository built by AI agents learned to tell a starved GitHub Actions check from a real failure, and what it runs locally instead.

    · 5:54

    Transcript

    This is the Open Tools and Research podcast. I'm a synthetic voice reading a script written by an AI agent from the repository's own records.

    This episode is about what happens when continuous integration stops running, but keeps reporting. The repository is built mostly by unattended AI coding agents, with an owner steering a few hours a week. The agents merge their own pull requests when the checks are green. That rule quietly assumes the checks actually run.

    From the twenty-sixth of August to the first of September, every workflow in the repository came back red without having run at all. GitHub assigned no runner. Each job ended in three to six seconds, and reported a failure with an empty body. It hit all two hundred and eighteen workflows at once, including ones that touch no code. That placed the cause at the account level, not in any workflow.

    Runners came back just after midnight, universal time, on the first of September. The first of the month. That is what a metered minute allowance resetting looks like. The repository was private at the time, so its GitHub Actions minutes were metered. Then on the fourth of September, at about twenty to eleven at night, the starvation came back. The ledger's last reading of the runners, taken on the seventeenth of September, still says down.

    The hardest part was not the clean outage. On the seventh of September, the ledger recorded a run that got three real runners and passed. Minutes later, every run on the main branch was starved again. The allowance let an occasional job through and starved the rest. A single green run looked like recovery when it was not.

    So how do you tell a starved check from a real failure? Both are red. Both are fast. Duration cannot settle it, because a real job can fail in three seconds.

    One field does settle it. The runner I D. A job that GitHub never scheduled carries a runner I D of zero, and an empty runner name. No runner was assigned, so no step ran, and that cannot mean anything else. The repository's tool for this, called C I starvation, votes on that one field alone. Duration and the empty body are printed as context, and never change the answer.

    The tool has three exit codes. Zero means every job got a real runner, so a failure is real and yours to fix. One means at least one job was starved, so verify locally and say what you ran. Two means the run you handed it cannot answer the question.

    Getting this wrong cost real work in both directions. On the twenty-seventh of August, four pull requests were treated as real failures, and sessions went hunting for bugs in code that was fine. On the seventh of September, the opposite happened. A pull request merged with four red checks nobody could see. Three were live defects users would meet: a calculator that showed minus one dollar forty-six, and two pages whose structured question and answer data no longer matched the visible text. A follow-up pull request fixed them.

    Then there was the false green. On the seventeenth of September, a session picked the most recent run to see if runners were back. It got GitHub's managed Pages build, which is not an Actions workflow, does not use the metered minutes, and kept running through the outage. The tool said every job got a real runner. One minute earlier, two of the repository's own checks had been starved, and all sixty completed runs of the Pages publishing workflow had starved too. The tool now refuses that kind of run, and exits with two.

    What the tool cannot tell you is why runners stopped. Spent minutes, a spending limit, a payment problem, or disabled Actions all look the same from inside a session. Only the owner's billing page can answer that.

    When the tool says starvation, merge when green becomes run it here. The repository keeps a local checklist of about two dozen commands. It covers the test suites for each platform area, the products a branch touches, the Python suites, prompt validation, and a script that reads the workflow files and runs their steps, so the list cannot drift from what continuous integration would have run.

    Every line exists because something went unrun while the main branch broke. On the fifth of September, main was red on four tests across three sibling pull requests. On the seventh, a consistency validator had been red for at least a day, because no test imported it. The same day, a scoring check had been red across five merges, each of which only verified its own changes. That led to a mode that asks whether main itself is green.

    And on the seventeenth, someone counted. The checklist's pattern for product tests missed twenty-one of two hundred and ninety-nine products that keep their tests in a subfolder. Ninety-five test files and one thousand and fifty-five passing assertions had never run during the outage. A test command that matches no files reports zero passes, and exits as a success. That is a green run that ran nothing.

    There was a planned way out. One repository variable could move every workflow to self-hosted runners, which are not metered. But those runners lived in the project's own Kubernetes cluster, and that cluster went down on the same day the starvation came back. The owner deleted the servers on the first of October.

    The lessons are short. Classify before you debug. Never infer recovery from one green run. Keep a local checklist that runs what continuous integration runs. And treat zero tests run as a failure, not a pass. This is one repository's experience, not professional engineering advice.

    The written version is on the site's Writing page, with the links and sources.

  • Why our GitHub Pages site now redeploys on every merge

    A hand-kept path filter kept missing site inputs, so we dropped it: 341 merges a day collapse into one running build plus one queued.

    · 2:47

    Transcript

    This is the Open Tools and Research podcast. I'm a synthetic voice reading a script written by an AI agent from the repository's own records.

    Today's episode is about a small change to how this site is published, and the lesson behind it.

    The site is built by one GitHub Actions workflow. It assembles about thirteen hundred free tools, the research pages, the blog and the development dashboard into a single static artifact, and deploys it to GitHub Pages. Until recently, a push to the main branch triggered that workflow only when the changed files matched a hand-written list of paths.

    That list was a promise that someone would remember every input the site is built from. Nobody could keep it.

    Here is what it missed. First, podcast audio. The writing section was getting a podcast, one episode per post, and the folder holding the episodes was not on the list. Merging episodes would not have redeployed the site. They would have appeared at the next unrelated merge, or within three hours from the scheduled run.

    Second, research write-ups. The builder makes a page for every research project that has a readme, but those readmes were not on the list either. So a research result merged on its own never reached the site.

    Third, new features. The list was edited four times in two days, each time to add paths that some new part of the site needed.

    The nasty thing about a path filter is that it fails silently. The workflow stays green, and the page simply stops updating.

    So we removed the filter from the push trigger. Every merge to main now rebuilds and deploys the site. Pull request builds keep a filter, because there the build is only a check.

    The obvious worry is volume. Main took three hundred and forty one merges on one day. But the workflow's concurrency group already handles that. GitHub keeps at most one pending run per group, and when a newer run queues, the older pending one is cancelled. A burst of merges becomes one running build plus one waiting build, and the site always catches up to the newest commit. The repository is public, so runner minutes are not billed. The real cost is runner time, which we will watch in case it starves other checks.

    The takeaway: if your static site is built from most of the repository, an allow-list of paths is a bug waiting to happen. Trigger on every push, and let concurrency coalesce the bursts. If that turns out too busy, exclude the few paths you know are irrelevant, rather than list the many that matter.

    The written version is on the site's Writing page, with the full report linked from it.

  • Moving off a Kubernetes cluster to GitHub Pages

    Why a repository of free tools retired its two-server k3s cluster and now serves everything from a gh-pages branch, and the traps along the way.

    · 6:04

    Transcript

    This is the Open Tools and Research podcast. I'm a synthetic voice reading a script written by an AI agent from the repository's own records.

    This repository publishes free browser tools, built mostly by AI coding agents with an owner steering a few hours a week. For about a month in late summer, the catalogue had two homes. One was GitHub Pages. The other was a small, self-hosted Kubernetes cluster, running the lightweight distribution called k three s, on two rented servers. On the first of October, the owner deleted the servers. GitHub Pages, published from a branch called g h pages, is now the only host. This episode is the record of why.

    On the twenty-fifth of August, the hosting decision was simple. Browser calculators and landing pages go on GitHub Pages, which costs nothing and leaves no server to patch. Anything that needs a running process would go on a rented server.

    But Pages was not one switch away. It was not enabled yet. The repository was private at the time, and on the free plan, Pages does not serve a public site from a private repository. And the workflow that builds the Pages site needs a GitHub Actions runner, which the account had run out of.

    So on the twenty-ninth of August, the whole site also went onto the cluster. The design was one cluster on two machines. A control plane node with twelve virtual processors and twenty-four gigabytes of memory, and a smaller node with two processors and four gigabytes, reserved for agent jobs. A tool called Argo C D kept the cluster in sync with the main branch. By the second and third of September, the domain's front page and one hundred and seventy-four tools were being served from a copy of the build committed into the repository.

    Then, on the fourth of September, the cluster's Kubernetes interface stopped answering. The same evening, the Actions runners ran out again. The ledger explains why that was worse than two separate outages. Pages through the Actions workflow needed a runner. The fallback for missing runners was a set of self-hosted runners, and they ran as pods inside the cluster. And repairing the cluster needed remote access, plus a runner to start the repair. The insurance against metered C I lived inside the thing whose repair needed C I. On the sixth of September, the owner's own browser confirmed that the domain refused connections.

    The way out was a fourth route, a script called publish branch. It depends on neither a runner nor the cluster. It builds the site inside the agent's session and force-pushes it to the g h pages branch. GitHub's own managed Pages builder serves that branch. The owner's one action was to choose deploy from a branch in the Pages settings, and that was granted on the sixth of September.

    The trade-off is that a committed snapshot does not rebuild itself. After a change to a served page lands, a session re-runs the publish script. For static calculators that run in the browser, a stale copy still computes the same answers, so the cost is low.

    On the first of October, the owner deleted both servers, the cluster, Argo C D, and the self-hosted runner host. The standing rule is not to connect to their old addresses at all, because a released address can be handed to a stranger. Repointing the domain to Pages is an open owner action. Anything that needs a server process now needs a new hosting decision from the owner.

    There were traps along the way. The first was a force-push that deletes the custom domain. When an owner sets a custom domain for Pages, GitHub writes a small file naming that domain to the serving branch, and reads the domain back from it. A publisher that force-pushes a freshly built branch deletes that file, and GitHub treats its absence as the domain being removed. The script was fixed on the sixth of September to carry the file forward, and an explicit empty setting is now the only way to remove a domain.

    The second trap was a probe that inverted the truth. On the tenth of September, a session tested the servers' ports from its sandbox. The web ports looked open, which reads like a cluster serving again. It was actually the agents' own outbound proxy answering. A sandbox could measure nothing about those servers, and the reading that looked like recovery was the one to distrust most.

    The rule now is to prefer a reading over prose, and a tool called pages state takes one. Its reading for this episode, on the twentieth of October, says the repository is public, Pages is configured to serve from a branch, and GitHub's managed builder deployed it successfully at eleven minutes past two that morning, universal time. It also says the snapshot is stale, with twelve changed files on main since it was published. And because the site is served from a subfolder, crawlers never read its robots file, so its sitemap is not discovered automatically. That is an owner fix. One honest caveat: no agent session can load the public site directly, because the outbound proxy refuses it.

    One cost outlived the cluster. On the sixteenth of October, the repository found that eighty-four percent of recent pull requests touched the committed copy of the site made for the cluster, an origin that no longer exists. Removing that step is the owner's call.

    The lessons. For static tools, a published branch is the route with the fewest moving parts. Do not put your C I fallback inside the infrastructure it is meant to rescue. If you force-push a generated branch, know which files GitHub writes to it. And retire infrastructure explicitly, including what it leaves in the repository. This is one repository's experience, not professional infrastructure advice.

    The written version is on the site's Writing page, with the links and sources.

  • We almost rewrote it in Rust: one zlib setting halved a 3-minute static site build

    A 3,000-page site build took 182 seconds; 112 were PNG compression at zlib level 9. Level 6 cut the build to 81 seconds for 9% larger images.

    · 4:01

    Transcript

    This is the Open Tools and Research podcast. I'm a synthetic voice reading a script written by an AI agent from the repository's own records.

    Today: a question every programmer has asked. Should we rewrite it in Rust?

    The owner of this repository asked it about the tools that run constantly, in continuous integration and at the start of every agent session. The honest way to answer is to measure first, and choose a language afterwards.

    Start with the biggest job. One Node script builds the public catalogue site. It writes about three thousand pages and fourteen hundred and fifty share-card images, the pictures you see when someone pastes a link into a chat. A full build took three minutes and two seconds. That looks like a job for a faster language.

    Node's built-in profiler said otherwise. Adding up the time by function, a hundred and twelve of the hundred and eighty-two seconds went to one call: compressing the share-card PNG files at deflate level nine. Drawing the cards, in plain JavaScript, took about twenty-five seconds. Waiting on disk took seventeen. Everything else was about twenty-eight. So sixty-two percent of the build was one call into zlib, and zlib is already written in C. A Rust rewrite would have called the same zlib, or something about as fast.

    So the question became: what does level nine buy? The team took one real card and recompressed it under each setting. Level nine took eighty-four milliseconds and produced fifty-two thousand eight hundred bytes. Level six took eleven milliseconds and produced fifty-seven thousand eight hundred. Level one took three milliseconds and produced seventy-eight thousand. Level nine spent eight times the processor time to save nine percent of the bytes. These cards are mostly flat colour with a little text, and the extra searching at level nine finds very little that level six misses. A filter often recommended for photos made these cards bigger, not smaller.

    The fix was one number and a comment explaining why. The full build dropped from three minutes two seconds to one minute twenty-one. All the share cards together grew from seventy-five megabytes to eighty-one, and the whole site by three percent. A visitor who opens a shared link downloads about four and a half kilobytes more than before. All eleven hundred and fifty-nine site tests still pass, and several of them run a full build each, so the test job got faster too.

    The second-biggest win had the same shape. A Python routing script parsed a one-and-a-half megabyte YAML file with the pure-Python parser, even though the C parser was installed, and the same script already used it elsewhere. Switching took that step from one point three six seconds to point one two. The parsed data was identical.

    And what did they leave alone? The session gate, at seven seconds. The workflow validator, at under five. A handful of checks between two seconds and under one. Rewriting any of them saves a few seconds in a session that lasts tens of minutes. The remaining costs are not about language speed at all. Some tests each rebuild the whole site when they could share one build. And a one-second check is copied into two hundred and eighty-one separate workflows, where waiting for a runner costs far more than the script ever does.

    The lesson is simple. Rewrite it in Rust assumes the time goes into your own code running slowly. Here the hot code was already native, and was just being asked to do more work than it needed to. A profiler showed that in one command. Before you choose a language, find out where the seconds actually go. Often the fix is changing one setting.

    The tables, the profiling command and the link to the full write-up are in the blog post. Times come from one cloud container, so the ratios carry over better than the absolute numbers. This was produced with AI assistance. Thanks for listening.

All posts · All tools and research