Most of my product work lives in private repositories: LILA, and my employers'. In September 2026 I took the parts of that work that could stand alone and published them as five small packages. Each one is a method I had already used in production or in my own evidence, cleaned up so it runs anywhere, with tests, continuous integration on three operating systems, and a README that says what the tool cannot do.

At a glance

  • product-engineer: a pack of four agent skills for Claude Code, Codex, Cursor and the other agents npx skills add knows about. The main skill carries seven rules: restate the request as a customer outcome before building, end every commit and pull request with a plain-language "For the customer" block, treat "done" as observed rather than as "tests pass", write down what was deliberately not built, never print a number that was not counted, speak the stakeholder's language, propose the smallest change that moves the metric. Three smaller skills install the commit block, the observed "done" and plain-language release notes on their own. A check command refuses a message without the block, and it ships as a commitlint plugin and a pre-commit hook; the plain-language table exists in Turkish, Japanese and Chinese. An evaluation of eight tasks, each run bare and with the skill, is in the repository with every transcript: the customer block went from 0 of 8 commits to 8 of 8, and two of the five metrics did not move and are printed anyway. npx product-engineer at 0.3.4.
  • proactive-gate: LILA's delivery gate as a zero-dependency library. Twelve checks in a fixed order, a reason on every rejection, the daily budget consumed by an atomic increment at send time, fail-open or fail-closed on store errors, and a replay command that runs a day of candidate messages through a policy and reports the allow rate and the silence reasons. Since 0.2.0 a policy is a JSON file with a schema, fifteen presets carry platform quotas and legal limits with their sources (LINE, WeChat, Kakao, Korean and Japanese law, India's TCCCPR, TCPA, ePrivacy), four adapters plug into the AI SDK, Mastra, LangChain and OpenAI Agents, a Claude Code hook gates tool calls, and a Python sibling in the same repository passes the same 33 conformance fixtures. A bench replays a committed day of 21 candidate messages through the gate and through an honest hand-rolled policy: 11 sent against 13, with each disagreement traced to a daylight-saving boundary, a budget keyed to the wrong day, or two deliveries taking the last slot at once. Quiet hours can differ per weekday, so a Friday-and-Saturday weekend or a Friday-evening rule is a configuration rather than a custom check. Since 0.4.0 explain(decision) renders that same decision as sentences for the person deciding whether the assistant is too chatty rather than for the engineer holding the trace, built from the trace with nothing added and identical word for word in both languages, which a cross-language check in continuous integration compares on every push; it was contributed by someone I had never spoken to, who came back hours later with the India preset: TRAI sets no statutory quiet window, its Schedule-II keeps four of nine time bands off until the subscriber switches one on, and the "9am to 9pm" every secondary source repeats is in no primary text, which is why that preset is opt-in consents rather than a window. Of its twelve defaults exactly one, the deferral constant, rests on a measured study, and the README names the trust ramp, the dismissal cooldown and the daily budget as judgement with no study behind them. npm i proactive-gate at 0.5.0 and pip install proactive-gate at the same version, with a docs site and playground.
  • workproof: a verifiable engineering report from a repository you cannot show. Figures from git (tenure, commit share, cadence, footprint, tests and docs, surviving lines, and since 0.2.0 files authored, major-contributor components, commit size, co-authored commits, absence factor, AI-assisted commits and survival by cohort), the exact command behind each and what each cannot show, no code, no paths, no emails by default. Bot commits leave every denominator and generated, vendored and lock files leave every count. The hash covers canonical JSON, check recomputes it, verify compares integrity before figures, and attest writes a signed statement. The README publishes a table of how the figures respond to gaming, including the tool's worst case: an unmarked generated file takes surviving lines from 51.6% to 99.3%, while the same file marked linguist-generated leaves every count. Calendar figures are computed in the author's own weeks rather than in UTC, which changed published numbers and therefore report hashes; the repository says so rather than letting a stranger discover it. npx workproof at 0.4.1.
  • surviving-lines: the share of lines still alive at HEAD next to commit share, over a deterministic file sample. The method behind Showing ownership when the repositories are private, and workproof's only dependency. --markdown prints the table for pasting into an issue, contributed by someone I had never spoken to. npx surviving-lines at 0.1.7.
  • ai-slop-linter: a linter for the tells of machine writing in commit messages, pull request descriptions and READMEs. Twenty rules, eighteen of them from Wikipedia's guideline on signs of AI writing, each with a line number and a reason; fixes only where a fix cannot change the meaning; an Action, a commit hook and an agent skill. It lists tells and never guesses who wrote the text. The first run on my own READMEs gave one of them a C for bold labels in a rule list; that README was rewritten the same day to show the tool before explaining it, and the table in the linter's README keeps both scores. Precision is measured rather than asserted: five public-domain texts written before any language model grade A or B, five pieces of unedited model output grade F, and the eight findings on the human side are published rather than tuned away. npx ai-slop-linter at 0.1.4.

Why these five

Each answers a question I had to answer for myself first. How do I describe my share of a codebase I cannot open, in a way a stranger can check? How does an assistant decide when not to speak, and how does a second team reuse that decision? How do I get a coding agent to explain a change to the person who asked for it? How do I catch the phrases that make a reader stop reading before the text is out the door? The packages are those answers with the private parts removed.

What the first audit found

On the evening of the day they were published I had all five read by an agent whose only instruction was to find where the tools misbehave for someone who is not writing English on an American setup, and to prove each finding by running it rather than by reasoning about it. It came back with six, and every one was real.

Two of them were failures, not rough edges. surviving-lines and workproof both exited with an error and produced no report at all on any repository holding a filename stored in decomposed Unicode, which is routine for Korean and common for French, Turkish, Vietnamese, Portuguese and Spanish names committed from Linux. The cause took some finding: macOS writes core.precomposeunicode=true into every repository git creates on it, and that setting rewrites command-line arguments, so a path read out of the tree no longer matched the tree when it was handed back. The linter's score was meaningless outside the Latin alphabet, because it counted words with a pattern that only matched Latin letters. A Japanese document of three thousand characters counted as one word, hit the fifty-word floor and graded F on a single tell whatever its length; Arabic and Hebrew counted zero.

The other four were quieter and, for a tool whose whole argument is that a stranger can trust the number, worse. workproof counted cadence in UTC weeks rather than the author's, so a developer in Auckland who worked two weeks appeared to have worked three. Author matching missed a name stored in a different Unicode normalisation, and İSMAİL YILMAZ could not match itself, because an uppercase dotted I lowercases to an i with a combining dot rather than to the Turkish dotless one. Fixed-width tables were padded by counting code units, so East Asian names pushed the numbers out of their columns. And the linter read an ordinary nested Markdown list as a spaced hyphen, which gave any README with nested bullets three errors and an F, on the day before it was to be shown to strangers.

A seventh finding came from reading rather than running. proactive-gate attributed its utility threshold to a system called PRISM. The system in the paper it cites is called Priorities, and PRISM appears neither in that paper nor on its author's publication index. The mathematics was never wrong; the name was, and a wrong citation in a README is a claim like any other.

All seven are fixed and released. Each fix carries a test built from the audit's own reproduction, and the two that changed published numbers say so in the changelog rather than leaving it to be discovered.

Where this stands

All five were published on 5 September 2026 and all five install from npm; each has shipped several releases since. This page used to say the version numbers lived on the npm pages rather than here, because here they would rot — and the five it still carried had rotted anyway, every one of them wrong by the time anybody looked. They are now compared against what npm and PyPI actually serve, along with the contribution counts, by a script that runs before a commit can be made; the honest fix for a number that goes stale is not to stop writing it down, it is to stop writing it from memory. proactive-gate's Python sibling is on PyPI at the same version, published by the same workflow. Every release is also archived on Zenodo with a permanent identifier, so a paper or a report can cite the exact code it ran and still resolve to it years later. Each is published by its own release workflow rather than from my machine, so npm carries build provenance linking the tarball to the commit and the workflow that built it. The launches are scheduled over the following days.

Within hours of the good-first-issues going up, two people I had never spoken to sent four pull requests: a SQLite store and a weekly budget for proactive-gate, more languages and a --format flag for workproof. A third sent the Markdown output for surviving-lines later the same day. The next day one of them came back: told that his SQLite store had shipped and asking to be pointed at more work, he took the issue for exporting proactive-gate's store contract as a suite anyone can run against their own store, and had it merged the same day. A week later a fourth person arrived from the opposite direction. proactive-gate had filed an issue against itself, admitting that its SQLite store deleted an expired row only when a read touched it, and that the keys it writes most carry the date, so nobody ever reads yesterday's key and nothing ever deleted it. He took that issue and sent the fix twelve minutes later, in TypeScript and Python together, with the test whose absence had hidden the bug: advance the clock, do not read the dead keys, count the rows. It was verified before it merged rather than taken on trust — with only his four new calls removed, exactly his two tests fail and nothing else does — and the measurement he had not supplied was taken here: the sweep costs about one percent on the path the library actually runs. Released as 0.3.1 the same morning.

Nine merged pull requests from four contributors; each was reviewed, run through continuous integration and merged the same day, with credit by name in the changelog. Nobody has starred any of the repositories yet.

Two rules make that repeatable, and they are written into every contributing guide now rather than left as a habit. A contribution is checked rather than admired: the contract suite was run against three stores each broken one way before it was merged, and the throwaway code that did the checking was handed to its author. And the person is told when their work ships, with the version and the install command, because a merge is a promise and a release is the thing they can show somebody.

All five run the same maintenance setup: actions pinned to commits, least-privilege tokens, a package gate that installs the tarball before a release exists, workflow static analysis, an OpenSSF Scorecard, dependency updates that merge themselves when green, and a nightly job that records stars and downloads. One release command bumps the versions, dates the changelog and pushes the tag; the workflow publishes and then installs the published package from the registry on Linux, macOS and Windows to check it runs. Every figure in the READMEs comes from a real run on a named public repository at a named commit, so the examples can be reproduced. Adoption, if it comes, will be recorded on the stats page with the same scope-and-method rule as everything else on this site, and not before.