What I'm focused on right now, and what's actually shipped, newest first. If it's
on this list, it ran. Subscribe via RSS.
buildingA pool runner for agents: several agents take the same task in parallel, each on its own branch, each allowed to run the task's own check while it works and kept off protected paths, and a run can land the passing branch when it finishes. It now runs in the background past a closed terminal, keeps finished agents when a run is interrupted, re-runs only the agents that failed, and can be followed to its end from any directoryrepositories in the workspace30+automations live3updated
Building now
A pool runner for agents: several agents take the same task in parallel, each on its own branch, each allowed to run the task's own check while it works and kept off protected paths, and a run can land the passing branch when it finishes. It now runs in the background past a closed terminal, keeps finished agents when a run is interrupted, re-runs only the agents that failed, and can be followed to its end from any directory.
Operator Loop in a drain phase: the queue of decisions waiting on a human is the constraint, so the permitted work is whatever shrinks that queue or costs the human nothing, and the instruments that measure the queue are getting the same scrutiny as the things they measure. "Build nothing" is a valid week, and a healthy one.
Shipped
50 ships in the last 6 months
· busiest month: Aug 2026 (15 ships)
Ships per month, Apr 2026 through Oct 2026:
Apr 2026 2, May 2026 2, Jun 2026 3, Jul 2026 8, Aug 2026 15, Sep 2026 15, Oct 2026 7.
Ships-per-month table
Month
Ships
Apr 2026
2
May 2026
2
Jun 2026
3
Jul 2026
8
Aug 2026
15
Sep 2026
15
Oct 2026
7
October 2026
Waiting on you, not broken
The status feed now tells a fault from a decision. A state only the operator can change, such as a pending review finding, a staged order or a permission only a human can grant, posts as ok with a message that names the action, and the dashboard lists it under its own heading instead of the Faults list. The attention digest stopped presenting its own failures as decisions, and the repair lever sends each fault to the repository that owns it.
#build-in-public#loop
The tax estimator reads the rest of your tax forms
One button now takes every form you have, names each one, and opens it in the reader for the card it fills: a 1099-NEC fills business revenue, a 1099-G fills unemployment and a state refund, a 1099-Q fills 529 withdrawals, a 1098-T and a 1098-E fill the education lines, a 1099-C fills canceled debt, a W-2G fills gambling winnings, a 1099-MISC fills prizes and other income, and a Schedule K-1 fills partnership and S corporation income. Each is read on your own device from a PDF or pasted text, previewed before it fills anything, and never stored.
#build-in-public#tools
The tax estimator reads your W-2 and your broker 1099
The public tax estimator now fills its own cards from the forms you already have: a W-2 fills this job or another job, a broker's consolidated 1099 fills interest, dividends and fund payouts, and its 1099-B summary fills the capital gains lines, pasted as text or read from the PDF on your own device, with every line previewed before and after and nothing stored. A job still going is projected to December from its latest paystub, with pay changes, bonuses and the 401(k) limit. It also compares an S corporation election, keeps a business with the spouse who runs it, and covers the dependent care earned income test.
#build-in-public#tools
The tax estimator covers stock options, Medicare premiums and the filing calendar
More of the return is live on the public tax estimator: nonqualified stock option exercises with their withholding, governmental 457(b) deferrals, opportunity fund gains coming due, Social Security back pay refigured over the earlier years it belongs to, income repaid from an earlier year, Medicare premium surcharges two years out, a check of a joint return against two single returns, the kiddie tax, children of separated parents, REIT dividends, business vehicles and equipment, moving expenses, the home EV charger credit, and a tax calendar that saves every upcoming deadline to your own calendar. Each shows its working on the results.
#build-in-public#tools
The fleet notices when its login expires
The background agents share one login, and when it expired for about a day and a half every session they started answered its first turn with a login error. Some of those sessions kept their status as running and their capacity slot after the login came back, and the fleet scored them as idle work. A sentinel now checks the login every five minutes, stops only sessions that a dispatcher started and that died at the login error, makes the self-healing layer wait instead of burning re-runs, and puts the one human step at the top of the operator's list.
#build-in-public#fleet#reliability
The tax estimator covers retirement withdrawals, carryovers and property sales
More of the return is live on the public tax estimator: required minimum distributions and inherited IRA minimums with the excise on a shortfall, excess IRA, HSA and 401(k) contributions, Roth IRA distributions, net operating loss carryovers with the California suspension, installment sales, like-kind exchanges, California real estate withholding, small business stock losses, collectibles gain, the credit for tax paid to another state, and a card that carries this year's leftovers into next year. Each shows its working on the results.
#build-in-public#tools
The site now says who actually publishes it
Five places on this site still said nothing reaches this site without a person deciding it should. That stopped being true in July 2026, when an unattended agent began publishing most of the essays inside a gate a person set. The about page, the colophon, the stats scoreboard and two easter eggs now describe the real rule: no person approves each post, every push has to pass the full guard suite and the build first, and CI re-runs the redaction guard behind every push, whoever made it.
#build-in-public#site
September 2026
The tax estimator covers health coverage, homes and retirement accounts
More of the return is live on the public tax estimator: the premium tax credit for marketplace coverage with its cliff, the saver credit, unemployment pay (which California excludes), the home sale gain exclusion, the home mortgage interest limit, rental losses held back by the passive loss rules and a rental sale taxed in its separate slices, nondeductible IRA basis with the pro-rata rule for Roth conversions, a per-spouse IRA deduction, the foreign tax credit, and credits for solar, batteries and home energy upgrades. Each shows its working on the results.
#build-in-public#tools
The tax estimator reads business income and the less common forms
The public tax estimator now takes partnership, LLC and S corporation income from a K-1, with California elective pass-through entity tax priced both ways, the small business stock exclusion, employee stock purchase plan sales split between wages and capital gain, IRA gifts sent straight to charity, gambling winnings and losses, alimony under agreements from before and after the federal repeal, the adoption and clean vehicle credits, household employment taxes, educator expenses, excess Social Security withholding across several jobs, and the California renter credit. Each shows its working on the results.
#build-in-public#tools
The tax estimator covers school, retirement income and medical costs
Four more parts of the return are live on the public tax estimator: education credits on Form 8863 (American opportunity and lifetime learning), the student loan interest deduction with its phaseout, Social Security taxed under the federal formula alongside pensions and tax-exempt interest, and the medical and dental expense deduction with California's own column for HSA-paid costs. Each shows its working on the results.
#build-in-public#tools
A second engine joined the build fleet
The build fleet now runs a second engine beside the first: a different vendor's model on its own subscription and its own concurrency cap, working the repair queue and executing plans the first engine left unexecuted while it was rate-limited, with one worker per repository across both and a pause of its own. Its sessions are booked in the same value ledger, labelled by engine, and the weekly throughput row reports each engine separately.
#build-in-public#agents
The tax estimator carries losses and large gifts into next year
Two carryovers are live on the public tax estimator: a capital loss beyond the annual limit flows through Schedule D and the tool reports what carries into next year, with California's matching line; and charitable gifts now respect the federal percentage ceilings by kind of gift and recipient, carry the excess forward, and apply California's own cash limit, with next-year notes on the results.
#build-in-public#tools
Seven tax-law corrections from an outside review
A model from a different vendor reviewed the tax estimator's reading of the law, and all seven findings are fixed, pinned by tests and live on the public tool: the itemize election follows the lower liability in an AMT year instead of the larger deduction total, the childless earned-income credit honours the age-65 line the tool was already collecting, a business loss nets against wages before the floor, the Young Child credit needs a qualifying child under six, California's small-business exclusion from alternative minimum taxable income and the under-24 exemption cap are modelled, and a foundation rule was narrowed to the private non-operating kind.
#build-in-public#tools
Review findings became repair work
Every finding the reviewer from a different vendor files against a repository now becomes a tracked repair item, verified when fixed and recorded when dismissed, instead of a report nobody reopened. In the first pass under the new intake, dozens of findings closed across seven repositories in one day, among them the fleet dispatcher's two locks proving ownership instead of inferring it from age and the status service ordering events by parsed instant rather than stamp text.
#build-in-public#agents
The tax estimator learned the itemized deduction limitation that returns in 2026
A federal limitation suspended from 2018 through 2025 comes back for tax year 2026 in a new form: itemized deductions fall by two thirty-sevenths of the smaller of the deductions or the taxable income above the start of the top bracket. The tool already applied California's mirror of the rule and nothing on the federal side, so a 2026 itemizer over the line was billed too little. It now runs after every other limitation, on the capped and floored total; the itemize-or-not election weighs the limited figure, which can push a marginal itemizer back onto the standard deduction; the qualified business income deduction is refigured on the limited amount; and the alternative minimum tax reverses the haircut, so in an AMT year the limitation costs nothing. Every 2025 profile and every 2026 profile under the line is unchanged, checked by running the previous engine beside this one across 1,152 profiles.
#build-in-public#tools
This site and the tax estimator pin HTTPS
Both public names now send the header that tells a browser to stop trying plain HTTP for them for a year. One sighting is enough: a browser that once reached the name over plain HTTP rewrites the remembered address before it makes any request, which ends the not-secure warning a first visit over an old link could still produce. The header came out of a new defensive check that reads what the internet actually gets from every name I publish, rather than what the server was configured to send.
#security#build-in-public
The defender searches for the bytes of every credential it declares
One check starts from the credentials each machine declares in its configuration and looks for those exact bytes everywhere they are not supposed to be: the transcripts the coding agents leave behind, shell histories, temporary directories, the clipboard, browser stores, app data and caches, binary files included, and every repository with its history. For a transcript it names the call whose output carried the value. It runs on both machines; the laptop has no GNU grep, ripgrep or node, so its leg is a perl script that takes its roots and needles on standard input and never holds a secret in an argument or a file. A file over 1 GiB is skipped and reported, never read, and a needle is matched on its first 255 bytes and confirmed whole at the match, which is what keeps the regex engine on its fast path.
#security#monitoring#guardrail
The tax estimator learned the two 2026 charitable rules
Two federal changes that start with tax year 2026, the year the tool defaults to: a filer who does not itemize can deduct cash gifts to public charities up to $1,000, or $2,000 on a joint return, and an itemizer's gifts count only above half a percent of the contribution base. The default year had been wrong in both directions, too high a bill for a standard-deduction giver and too low for an itemizing one. The deduction sits below adjusted gross income, so it moves taxable income alone, proved by running the previous engine beside the new one across 1,200 profiles with zero differences anywhere else; the itemize-or-not election is now a three-term comparison, which flips a marginal itemizer back onto the standard deduction.
#build-in-public#tools
The decision queue asked git how old its rows were
The weekly queue of decisions waiting on a human sorts each tier oldest first, and it took a row's age from the first date anywhere in its prose. Thirty-four of a hundred rows mentioned no date and had no age, thirteen carried a wrong one, and the two oldest hard gates in the queue sat at the bottom of the first tier at 96 days with no age at all. Every row lives in a git repository, so its age now comes from blame on its own heading line, held exactly since the commit that added it; the prose date survives only as a fallback. Ageless rows went from 34 to one, and the whole blame pass costs about half a second across thirty files.
#build-in-public#loop#tools
The tax estimator learned four more schedules
The federal earned income credit with California's CalEITC and Young Child Tax Credit, California's prior-year minimum tax credit, California's itemized deduction limitation, and all four parts of the new federal Schedule 1-A: qualified tips, the overtime premium, the enhanced senior deduction and new-vehicle loan interest, each with the phaseout the form actually computes, including the one that steps down in fixed increments rather than sloping. Every figure is checked against the published instructions in the test suite, and the deploy runs that suite before anything goes live, so a red build cannot ship.
#build-in-public#tools
The stop button got its capability back
The lever that pauses a fleet of coding agents stops them by creating a single file, and a hardening pass had given the page's server a read-only view of the directory that file lives in, which was the correct restriction and also the end of the stop button. It failed on every tap for a week, reporting the filesystem error faithfully to a reader who was asking a question about agents rather than about storage. The repair is not a wider hole and not a relocated file, both of which were tried on paper and rejected: pause and resume are now two declared units that do exactly one creation and one removal and nothing else, run outside the page's sandbox under their own restrictions, reached only when the filesystem refuses the direct write. The state that comes back is re-read from the file rather than inferred from which path answered, so a unit that runs cleanly and changes nothing counts as a failure.
#reliability#guardrail#automation
A powers-of-ten journey got a page of its own
The Planck length grows tenfold a second while the observable universe shrinks tenfold, and after 30.868 seconds both land on the size of an early human embryo. /scale plays that out as one instrument: two lenses with a hand-drawn portrait of every benchmark object along the way, a log rule under each showing how far the moving scale is from it, and a full ledger of every whole-second comparison with its source. Approximate objects, exact powers.
#site#visualization
August 2026
The scheduled jobs finally got a supervisor
The long-running services here had two watchdogs between them. The scheduled jobs had none, so a failed run could sit failed for days with nothing noticing. A repair daemon now sweeps them every few minutes: it re-runs what a re-run can fix, under a strict per-job attempt budget, and escalates rather than looping on what it cannot. Its first night repaired three failures on its own and escalated one when the budget ran out.
#automation#reliability#guardrail
The scanner was wrong about reachability in both directions
The defender that inventories my own machines answered one question, what can be reached from off this box, with two different wrong answers on the same morning. Its packet-filter reader summed destination port ranges without reading the protocol column, and because ICMP has no ports the compiler writes 0 through 65535 into that field as a placeholder, so a single rule permitting ping counted as admitting every port and outvoted the twenty-six real ones; the header read 65,536 admitted ports for weeks after the policy had been narrowed, and UDP listeners were matched against TCP rules for the same reason. In the opposite direction, its exposure grading read bind addresses, so eight services sitting on loopback behind a proxy that publishes them graded as not network-facing and sorted to the bottom of the report as the safest things running. The parser now carries the protocol, ranges with no TCP or UDP protocol are excluded from the port arithmetic while missing protocol data still counts so an absence can never hide a blanket rule, exposure grading intersects each unit with the proxy map, and an unreadable map reports as unreadable rather than as nothing published. Verified from a second machine by watching a connection to a removed port hang until it timed out.
#security#monitoring#networking
The handshake that would sign anything you handed it
A bridge that turns a live meeting into text has to satisfy the meeting platform's mandatory webhook setup: the platform sends a random token and you return an HMAC of it under your secret to prove you hold it, and that same secret signs every later event over the string v0:timestamp:body. The setup responder placed no constraint on the token it would sign, so its input space swallowed the signature format's, and handing it v0:timestamp:body returned the exact signature that authenticates a forged event: an auth bypass built by following two separately documented steps that are each correct on their own. The responder now refuses any token carrying a colon or longer than a real one, restoring the domain separation that had never been drawn between the two kinds of message. Two lesser findings closed in the same pass: a validly signed event could be replayed indefinitely with no timestamp window, and an outbound socket target lifted from the payload was opened without checking it pointed at the platform at all. The service had shipped disabled, so nothing was exposed.
#security#cryptography#build-in-public
A second opinion that does not share my blind spots
Nearly every line of code in this workspace is written by one model and mostly reviewed by the same one, which catches a great deal and leaves the author and the reviewer sharing a set of things neither thinks to look at. The evidence was dated: a charter rule saying the presence of an environment variable is diagnostic evidence and never authorization, then a tool shipped seventeen days later with precisely that hole, unremarked by every review in between. A read-only wrapper now runs a different vendor's model over a diff with the intent behind the change fed in beside it. Its first run was pointed at itself and returned six defects in code that already had sixteen passing tests: two were holes in the tool's own two guarantees rather than ordinary bugs, and two were in argument-parsing code that lived inside the executable where no test could import it. A second review over the repaired code confirmed five fixes, disputed one, and raised three more, of which the most useful could not be reproduced from four directions and was acted on regardless, since marking a repository trusted in order to review it is backwards whether or not the trust currently buys anything.
#build-in-public#tools#agents#ai
A fourth home system, and the first one that cannot act
The home automation family was three planners built dry-run first (irrigation, climate, energy dispatch), each able to actuate only when a human sets a flag and an environment variable in the same command, with on/off-grid switching left as a suggestion whose actuation function is written to refuse. It gained a fourth member of the opposite shape after two of four solar strings sat disconnected through a clear afternoon while the array went on producing a perfectly plausible number, which no planner reading that number could have questioned. The new monitor is read-only by construction: it diffs per-string state and the hardware's own alert list against the last healthy baseline, and refuses to record an already-broken array as the normal baseline on a first run. The irrigation planner stopped deciding from tomorrow's forecast alone and now keeps a rolling soil-water balance for each zone, which is the thing that knows the ground is still wet from last week. Two of the four read live data. The other two still plan against sample fixtures every morning and print which one they read above every recommendation they produce.
The watchdog found out what green had been measuring
A status service put a credential in front of its read surface, where 48 of 67 routes had been answering anyone who could reach it, and several browser-facing services moved behind a shared fail-closed gate on the same afternoon. The monitor that watches those services holds restart authority and expected a 2xx on an anonymous GET, so it read four correctly gated services as wedged processes and restarted them on a loop. Accepting a 401 as healthy everywhere would have been one line per entry and left every probe watching the gate rather than the service behind it, so each was repointed instead: at a deliberately anonymous liveness route where one exists, and at both hops separately where a proxy sits in front. Two quieter checks were caught in the same pass, a pre-restart preflight that tolerated a 4xx and so would have reported all 33 of its probes passing while parsing nothing, and a freshness probe that fails safe and would have reported the answer unknowable forever.
The transcode learned how many people were waiting
The home video library had two cleanup paths that both guessed at the same missing fact. One killed too little: subtitle extraction spawned an ffmpeg pass per track, none of them owned by the job, so cancelling removed the encoder and left the passes reading a 4.7 GB file for a request nobody was waiting on, and each retry stacked three more readers onto the drive already feeding the next attempt. One killed too much: the beacon a tab fires on close tore down the episode's jobs and deleted every built segment, so a second device lost its stream when the first one left, and a reload deleted the segments it was about to ask for. Per-tab viewer leases now ride the status poll that was already running, and a job survives until its last lease has been gone through a grace period. Subtitles come out in one pass into a per-episode cache, so a retry, a second device and the prefetch join the read in flight instead of racing it: a cold play reaches its master playlist in about 104 seconds instead of about 420.
#reliability#self-hosted
Not affected, twenty-four times, and none of it meant anything
The security checker here now reads a vendor's own published OS security releases and answers whether this machine has the release that fixes what is being exploited. Day one it found a measured false clean: the Mac runs a pre-release build whose major version the vendor has published no security content for at all, so all 24 of that OS's entries in CISA's known-exploited catalogue could only grade not-affected or unverified. The comparison had no defect in it. A version above every published vulnerable range is a definite miss against every one of them, and an ordering test cannot distinguish being newer than the data from being outside it. The existing blind-spot detector could not catch it either, because it watches for a check that reports nothing and this one reported 24 correct verdicts. The fix was vocabulary: a patch-state ladder with four refusals in it, an uncomparable release counted rather than dropped, a definition version ahead of published carried as evidence instead of graded, and a switch missing from a preference file reading unknown rather than off.
#security#measurement#build-in-public
Three services stopped answering the network
Every browser-facing service here now sits behind a TLS front with a real hostname and a real certificate, and three of them narrowed their own bind from the private network address to loopback, so the front is the only thing that can reach them. The trigger was cosmetic: a browser tries HTTPS first, a bare numeric address can never match a certificate, so a page one person opens carried a permanent not-secure warning. Substituting a name for a number re-opened three decisions underneath it. A dev server's rebinding guard admits any numeric literal and refuses any hostname not explicitly listed, so the extra names now arrive from the environment and never from the published config. The daemon serving the name holds that port, so a service still binding it raced its own front on every restart, the loser either crash-looping or fronting nothing. And a dev server that quietly moves to the next free port when its own is taken now refuses to start instead, because a supervisor and a proxy both depend on the port it was given.
#security#reliability#build-in-public
The first real verdict was a refusal
A factor research engine whose product is the verdict rather than the backtest ran against the actual market for the first time, after synthetic worlds with known answers. The backtest looked strong and the machine rejected it anyway: across nearly five years of price history none of the 400 companies in the universe had stopped trading, which is the signature of a universe assembled from survivors, so the mandatory data-integrity audit blocked certification before any performance number was considered. The gate thresholds had been committed to version control nine minutes before the run, so the verdict could prove they were not chosen after seeing the result. Nothing was acknowledged away and no threshold moved.
#research#validation#build-in-public
An outage age the buffer could not grow past
The daily briefing printed two different ages for one broken automation, two blocks apart on the same page. The shorter figure measured the horizon of the 500-event ring that almost everything reads, not the outage, so a problem of any age reported roughly the ring's own span and then stopped growing while the incident kept aging. The onset the durable archive remembers is now carried alongside it, without re-keying the value that acknowledgements and the transition journal use as an episode's identity. Reliability rows gained the counts they were judged on over the whole record, so a source that has never once reported success reads differently from one that regressed to the same zero, and a floor loosened by hand now records why and proposes lifting itself once its source recovers.
#monitoring#reliability#build-in-public
A megabyte off every page open
Fifty-seven percent of the projects dashboard was a baked snapshot that every cold load downloaded and then overwrote with a live copy, for a view the page does not start on. It had been a month out of date the whole time, and being overwritten is why that never showed. The bake now writes the twenty highest-scoring entries and states on the page how many it left behind, the live fetch waits until that view is opened, and a cold load fell from 1.09 MB gzipped to 0.32 MB. A payload budget re-records itself downward whenever the page shrinks, and a refresher re-bakes the snapshots that had sat 24 and 33 days stale, refusing to run when the working tree holds changes it does not own.
#performance#automation#build-in-public
Docs that point instead of copy
A guide that keeps its own copy of a live value goes wrong silently and stays wrong: one line named a default the code had changed 28 days earlier. Twenty repositories now cite the file that owns each value instead of restating it, and a weekly report-only checker compares whatever the docs still restate against its source.
#documentation#automation#build-in-public
The news reader got a memory
Value triage is deliberately bounded and retention deletes at 30 days, so the engine kept no history of what it had judged. A standalone catalogue keyed by article URL now accretes every article and score and survives the prune, and a companion pass scores the whole unscored backlog oldest-first with the age gate lifted. A separate vetting pass reads a candidate feed in full and routes it through the source pool's own transitions, so a feed earns its slot on evidence instead of a queue position.
#newsagg#pipeline#build-in-public
The site grew a night shift
After the visitor's local midnight the dark palette sinks darker, a night-shift log surfaces in the footer, and the favicon swaps to a moon. Five after-dark essays now hide faint stars that assemble into a constellation, a word, and a sealed room; the 404 page grew a tiny Pong court; the browser console learned to talk back; and a retro mode waits for anyone who draws the parallelogram.
#site#fun#build-in-public
July 2026
The site made its own claims checkable
An accountability page now separates what on this site is independently verified from what is self-reported, /stats publishes the method behind the time-reclaimed number before the number itself, and every project page states how much of its source is published and how deep the write-up goes.
#trust#transparency#build-in-public
The build fleet gained a legible, dependency-ordered ready queue
Each repository's backlog now triages into a scored, dependency-ordered queue instead of agents guessing what to pick up next. Shipping it surfaced a same-day insight: the queue's machine-readable data now lives in its own JSON file instead of being re-parsed out of the markdown written for a person to read.
#agents#automation#seams
NewsAgg ranking rebuilt on an auditable merit engine
A single holistic model judgment was replaced with a portfolio of roughly 100 independently tested scoring signals fused into a merit score, and every ranked item now shows its work: a plain-English receipt naming what raised and lowered it, or an honest admission when the engine can't say.
#news#ranking#trust#build-in-public
Home Movies and Music Box went live: private, on purpose
Two fully-featured personal apps shipped: a family video library with autoplay and on-demand HLS transcoding, and a FLAC library with full-text search and direct byte-range streaming. Both reachable from the house LAN and over Tailscale, neither ever getting a public URL.
#self-hosted#media#privacy#build-in-public
NewsAgg went live
An AI news aggregator that clusters the same story across outlets and surfaces where they disagree (the cross-source friction, not the consensus) shipped at newsagg.parallelogramist.com.
#news#clustering#build-in-public
This site went fully live, with an automated deploy pipeline
parallelogramist.com now serves on its own domain, and every push to main runs the type-check, the full guard suite (redaction, link safety, accessibility), the build, and the deploy. The push itself stays a deliberate human act: the pipeline automates everything after the decision.
#site#build-in-public#infra
The fleet split planning from execution
Each repository's work is now planned by an agent on the strongest reasoning tier (it makes every judgment call and writes one executable plan file) and implemented by a separate agent on a cheaper, faster tier that follows the plan exactly. Forced by a real capacity crunch: a hard usage cap on the top tier had stalled whole batches of work.
#agents#infra
The fleet supervisor got a dead-man backstop
A reworded usage-limit message evaded the watchdog's pattern-matching and wedged every fleet slot for hours while the dashboard read all clear. The targeted fix teaches the classifier that message; the class fix presumes any agent that stays silent and unclassifiable for an hour is dead, and frees its slot.
#agents#guardrail
June 2026
The status service and dashboards hit v1.0
The central status service grew embeddable, glanceable surfaces (a reliability sparkline and a browsable status page), and the operator dashboard added reliability and activity charts plus a ranked triage queue.
#infra#telemetry
The loop turned to consolidation
A deliberate adopt-over-build phase: sharpen the existing toolset and reclaim time from what already runs, with new features a distant third. 'Build nothing' is a valid, healthy week.
#loop#method
Report-only home-routine planners, dry-run by default
A small set of around-the-home planners now run report-only: each proposes an action and logs it, but never actuates anything for real until a human signs that specific automation off. Safety-first, deny-by-default.
#automation#guardrail
May 2026
The public hub went live
parallelogramist.com (this build-in-public site) shipped: write-ups of every project, the loop methodology, and a /now snapshot of what's current.
#site#build-in-public
Family-time defense, live
The first always-on guardrail landed: an automation that defends protected hours, so the loop can never schedule over them.
#automation#guardrail
April 2026
Three report-only automations built
Defend, brief, and triage run report-only by default: they surface a recommendation; a human adopts each one before it ever acts.
#automation
The Operator Loop, scored
A scored leverage ledger turned the next-build choice into a ranked, upkeep-aware decision instead of a guess. Toil that costs more than it saves self-prunes.
#loop#method
Previous focus snapshots
The "building now" line as it read at earlier points: a momentum trail, not just one mutable sentence.
Building: An attention autopilot for the queue of items waiting on a human, which had reached dozens of rows and was growing faster than anyone could read it. Code decides the hard gates (money, publishing, anything physical, secrets, guard changes), a model only classifies the rest read-only, work that fits an agent is dispatched, rows that are already moot are closed through their own write paths with proof, and what remains arrives as a short ranked list of one-tap decisions. Next: proving the implement path from a rehearsal fixture while the fleet is paused, before it touches anything real
Last shipped: Giving the build fleet separate capacity lanes under one shared budget for the host: a single cap used to govern every agent dispatch, so a long planning run could hold the only slot for hours while every fix the operator had already approved was refused as at capacity, thirty times in a row. Each lane now has its own cap, all of them are bounded by the memory the host actually has free, and the roster gained priority tiers, so the most valuable repositories are staffed first without starving the rest
Building: Teaching the self-healing layer to tell a repair from a retry: a restart counts as repaired only once the restarted thing answers, every finding the supervisor posts says what kind of action it needs, and a healer facing a fault it is not allowed to fix, such as a license agreement an operating-system update reset, records the cause and the one command that clears it instead of restarting a healthy tunnel on a timer. Next: the privileged fixes those healers queue, which wait on a human
Last shipped: Making the fleet's own instruments engine-aware after a second engine joined it: the weekly throughput row reports each engine separately, and the evaluator that judges the fleet's experiments now refuses to decide on a cohort that mixes engines, so a registration either states which engines it draws from or waits, instead of adopting a change on a baseline that only measured which engine ran
Building: Running a second engine in the build fleet, a different vendor's model on its own subscription and its own concurrency cap, working the repair queue beside the first and picking up plans the first leaves unexecuted while it is rate-limited, one worker per repository across both. Its rows land in the same value ledger the fleet steers by, which is the point for deciding where attention goes and a confound everywhere else: the two engines' real-value rates sit seventy-eight points apart, and the evaluator that judges the fleet's own experiments pooled them, so a cohort straddling the new engine's first day measured which engine ran. The weekly throughput row is split by engine now. Next: the experiment evaluator, where a cohort will state which engines it draws from
Last shipped: Turning the reviewer from a different vendor into a source of repair work rather than reports: every finding it files against a repository is now a tracked item, verified when it is fixed and recorded when it is dismissed, and the fleet's review of its own sessions remembers each session by identity instead of by a timestamp cursor, so a session the reviewer skipped once is no longer lost for good. The first pass under the new intake closed dozens of findings across seven repositories in a day
Building: Turning the reviewer from a different vendor into a source of repair work rather than reports: every finding it files against a repository is now a tracked item, verified when it is fixed and recorded when it is dismissed, and the fleet's review of its own sessions remembers each session by identity instead of by a timestamp cursor, so a session the reviewer skipped once is no longer lost for good (twelve had been). The first pass under the new intake closed dozens of findings across seven repositories in a day: the dispatcher's two locks proving ownership instead of inferring it from age, the status service ordering events by their parsed instant rather than the text of the stamp, seven corrections to the tax estimator's reading of the law. Next: the findings that were filed as decisions rather than fixes, which wait on me
Last shipped: Reading, on a schedule, what the internet actually gets from every name I publish, instead of trusting what each server was told to send: whether a page arrives in cleartext, whether a door answers an error, which security headers are missing, whether the certificate log holds a certificate I never issued, and whether a script now loads from an origin it never used before. The first read found two tools served in cleartext and this site, the tax estimator and a third public page all missing the header that pins a browser to HTTPS, fixed the same evening across three repositories. The same pass dated the minutes a public page of mine had been unreachable the day before, eighteen of them in three episodes, which no gauge had reported: the check that looks for the process serving it had been running inside a sandbox where processes outside it cannot be read, and had filed that blindness as the process refusing to be read. Next: the other checks that read process ownership the same way, which are still blind from inside the sandbox and do not yet say so
Building: Reading, on a schedule, what the internet actually gets from every name I publish, instead of trusting what each server was told to send: whether a page arrives in cleartext, whether a door answers an error, which security headers are missing, whether the certificate log holds a certificate I never issued, and whether a script now loads from an origin it never used before. The first read found two tools served in cleartext and this site, the tax estimator and a third public page all missing the header that pins a browser to HTTPS, fixed the same evening across three repositories. The same pass dated the minutes a public page of mine had been unreachable the day before, eighteen of them in three episodes, which no gauge had reported: the check that looks for the process serving it had been running inside a sandbox where processes outside it cannot be read, and had filed that blindness as the process refusing to be read. Next: the other checks that read process ownership the same way, which are still blind from inside the sandbox and do not yet say so
Last shipped: Searching both machines for the exact bytes of every credential they declare, everywhere those bytes are not supposed to be: the transcripts the coding agents leave behind, shell histories, temporary directories, the clipboard, browser stores, app data and caches, binary files included, and every repository with its history. The laptop has no GNU grep, no ripgrep and no node, so its search is the system perl, chosen because its regex engine builds a trie over an alternation of literals and read 158 MB of transcripts in 0.7 seconds where BSD grep took 32. The first full run took 366 seconds instead of the fourteen budgeted, at 3 MB per second, slower than the grep it had beaten, because one of the strings being searched for is a 1,940-byte sign-in token and the engine stores a literal in a node holding at most 255 bytes, so the trie was never built and nothing said so. The regex now holds each needle's first 255 bytes and compares the whole needle at the match, and the walk over 154,928 files takes 18.8 seconds. The filed limits are the places a byte search cannot read as they lie: a compressed browser store, a keyring-encrypted login row, a value that was base64- or URL-encoded in transit
Building: Searching both machines for the exact bytes of every credential they declare, everywhere those bytes are not supposed to be: the transcripts the coding agents leave behind, shell histories, temporary directories, the clipboard, browser stores, app data and caches, binary files included, and every repository with its history. The laptop has no GNU grep, no ripgrep and no node, so its search is the system perl, chosen because its regex engine builds a trie over an alternation of literals and read 158 MB of transcripts in 0.7 seconds where BSD grep took 32. The first full run took 366 seconds instead of the fourteen budgeted, at 3 MB per second, slower than the grep it had beaten, because one of the strings being searched for is a 1,940-byte sign-in token and the engine stores a literal in a node holding at most 255 bytes, so the trie was never built and nothing said so. The regex now holds each needle's first 255 bytes and compares the whole needle at the match, and the walk over 154,928 files takes 18.8 seconds. The filed limits are the places a byte search cannot read as they lie: a compressed browser store, a keyring-encrypted login row, a value that was base64- or URL-encoded in transit
Last shipped: Making the weekly decision queue rank on the file's own history instead of on dates it happened to mention. Every repository keeps a file of the questions that need a human rather than an agent, a tool sorts them into tiers and oldest first inside each tier, and a row's age came from the first date anywhere in its prose, which is whatever the author was writing about: a measurement window, a cited incident, a deadline. Thirty-four of a hundred rows mentioned no date and so had no age, thirteen carried the wrong one, and the two oldest hard gates in the whole queue sat at the bottom of the first tier at 96 days with no age printed beside them. A row's age now comes from git blame on its own heading line, a date the repository has held exactly since the commit that added it, with the prose date kept only as a fallback; ageless rows went from 34 to one. The flag added so that tidying a file could not reset every row's age was checked without a control, and when the control was finally run it changed zero of the queue's answers, so the next pass is on the fix's own verification rather than on the queue
Building: Making the weekly decision queue rank on the file's own history instead of on dates it happened to mention. Every repository keeps a file of the questions that need a human rather than an agent, a tool sorts them into tiers and oldest first inside each tier, and a row's age came from the first date anywhere in its prose, which is whatever the author was writing about: a measurement window, a cited incident, a deadline. Thirty-four of a hundred rows mentioned no date and so had no age, thirteen carried the wrong one, and the two oldest hard gates in the whole queue sat at the bottom of the first tier at 96 days with no age printed beside them. A row's age now comes from git blame on its own heading line, a date the repository has held exactly since the commit that added it, with the prose date kept only as a fallback; ageless rows went from 34 to one. The flag added so that tidying a file could not reset every row's age was checked without a control, and when the control was finally run it changed zero of the queue's answers, so the next pass is on the fix's own verification rather than on the queue
Last shipped: Making the emergency controls survive the hardening that runs past them. The lever that pauses a fleet of coding agents works by creating one file, whose existence every scheduler scan and every dispatched job reads as stop, and nineteen days after it shipped a hardening pass gave that page's server a read-only view of the directory the file lives in. The same directory holds the hooks deciding what the agents may do, the settings behind them and a credentials file, so the restriction was correct and it silently revoked the one write the stop button needed. Every tap after that reached the right route, passed the origin check and the cookie, and died on the filesystem with the operating system's own sentence, which the page displayed and held on screen for six seconds while I filed the whole thing as a broken button. Two of the three available fixes were wrong: widening the hole hands a web-facing process the hooks and the credentials, and relocating the file quietly changes the meaning of the switch for the four other things that know its path. The third is to name the action rather than widen the sandbox, so pause and resume are now two declared units doing exactly that one creation and that one removal and nothing else, run outside the page's sandbox under their own restrictions, reached only when the filesystem refuses, with the reported state re-read from the file afterward rather than inferred from which path ran
Building: Making the emergency controls survive the hardening that runs past them. The lever that pauses a fleet of coding agents works by creating one file, whose existence every scheduler scan and every dispatched job reads as stop, and nineteen days after it shipped a hardening pass gave that page's server a read-only view of the directory the file lives in. The same directory holds the hooks deciding what the agents may do, the settings behind them and a credentials file, so the restriction was correct and it silently revoked the one write the stop button needed. Every tap after that reached the right route, passed the origin check and the cookie, and died on the filesystem with the operating system's own sentence, which the page displayed and held on screen for six seconds while I filed the whole thing as a broken button. Two of the three available fixes were wrong: widening the hole hands a web-facing process the hooks and the credentials, and relocating the file quietly changes the meaning of the switch for the four other things that know its path. The third is to name the action rather than widen the sandbox, so pause and resume are now two declared units doing exactly that one creation and that one removal and nothing else, run outside the page's sandbox under their own restrictions, reached only when the filesystem refuses, with the reported state re-read from the file afterward rather than inferred from which path ran
Last shipped: Deciding what "the live version" of a running service means, in the places where nothing ever decided it. A small server at home answers an API over a library of old console games and serves a directory of static files, and it carried two opposite bugs at once. The static half was served straight out of a live working tree that both I and the agents running against it edit, so a redesign reached an iPad one save at a time: a new index.html arrived six minutes before the app.js it was written against, a pairing that existed in no commit and never would. The code half had no reload watcher registered at all and kept serving what it booted with, three files behind, so a page updated to expect a paged response met an API still answering with a plain array and rendered an empty shelf. One process, one machine, two opposite convictions about what day it was, and the symptom for both was that reloading fixed it. The served files are now a git archive export of a commit, so every file moves together or none of them does, and an environment variable keeps the working-tree view for a test instance, the one case that actually wants a directory. That fix failed the other way eight minutes later: the thing that restarts a service after a commit watches the source directory, so a commit touching only the static one was never picked up and the pages 404ed on the theme and font they had themselves just committed. The export now follows HEAD and swaps in about six seconds with no restart, and the restart the code half still needs waits while a game is holding a connection open, because a restart mid-game is how somebody loses an autosave
Building: Deciding what "the live version" of a running service means, in the places where nothing ever decided it. A small server at home answers an API over a library of old console games and serves a directory of static files, and it carried two opposite bugs at once. The static half was served straight out of a live working tree that both I and the agents running against it edit, so a redesign reached an iPad one save at a time: a new index.html arrived six minutes before the app.js it was written against, a pairing that existed in no commit and never would. The code half had no reload watcher registered at all and kept serving what it booted with, three files behind, so a page updated to expect a paged response met an API still answering with a plain array and rendered an empty shelf. One process, one machine, two opposite convictions about what day it was, and the symptom for both was that reloading fixed it. The served files are now a git archive export of a commit, so every file moves together or none of them does, and an environment variable keeps the working-tree view for a test instance, the one case that actually wants a directory. That fix failed the other way eight minutes later: the thing that restarts a service after a commit watches the source directory, so a commit touching only the static one was never picked up and the pages 404ed on the theme and font they had themselves just committed. The export now follows HEAD and swaps in about six seconds with no restart, and the restart the code half still needs waits while a game is holding a connection open, because a restart mid-game is how somebody loses an autosave
Last shipped: Auditing the selection rules that sit between a ranking and what I actually read. A research loop reads seven feeds for advances in how people are building with language models, scores everything it pulls, and hands me the top three once a week. The selection was a slice off one global order, and a single product changelog holds ranks 1 through 8 unbroken and 48 of the top 60, so every batch was three consecutive bullets from the one source with 3,375 items pulled and nothing ever filed. All six findings the loop has produced in its life came from three feeds that slice could never reach. The repair is selection, not ranking: one pass takes each source's best unblocked stub before any source's second, the scoring config and the lane order come out byte-identical, the changelog still leads at rank 1, and the batch's combined fit score drops from 111.5 to 94.5 on purpose. Reaching past rank 8 then exposed what the old rule had been hiding. Five of the eight sources had a best candidate already past the loop's own 60-day freshness line, three of them by more than three months, because that test runs once at the instant an item arrives and nothing ever revisits it: 335 of 1,897 active candidates were stale while ranking ahead of the entire 1,011-item backlog, a share that climbed every day by construction. It never showed because an actively developed changelog cannot go stale, so the only input the freshness rule was ever enforced against was the one input incapable of breaking it
Building: Auditing the selection rules that sit between a ranking and what I actually read. A research loop reads seven feeds for advances in how people are building with language models, scores everything it pulls, and hands me the top three once a week. The selection was a slice off one global order, and a single product changelog holds ranks 1 through 8 unbroken and 48 of the top 60, so every batch was three consecutive bullets from the one source with 3,375 items pulled and nothing ever filed. All six findings the loop has produced in its life came from three feeds that slice could never reach. The repair is selection, not ranking: one pass takes each source's best unblocked stub before any source's second, the scoring config and the lane order come out byte-identical, the changelog still leads at rank 1, and the batch's combined fit score drops from 111.5 to 94.5 on purpose. Reaching past rank 8 then exposed what the old rule had been hiding. Five of the eight sources had a best candidate already past the loop's own 60-day freshness line, three of them by more than three months, because that test runs once at the instant an item arrives and nothing ever revisits it: 335 of 1,897 active candidates were stale while ranking ahead of the entire 1,011-item backlog, a share that climbed every day by construction. It never showed because an actively developed changelog cannot go stale, so the only input the freshness rule was ever enforced against was the one input incapable of breaking it
Last shipped: Auditing the places where a two-way test decides between actions of unequal cost. A builder I leave running unattended writes an improvement, runs the target repository's own verification, and rolls the attempt back when the result comes out worse. Rollback sorted every touched file into two buckets: tracked by git, restored with git restore, and everything else, deleted, because deleting a file you just made is what undoing its creation means. There are three kinds of file, not two. The third exists on disk and git has never heard of it: an environment file, a draft I had written but not added, anything named in the ignore list. It failed the tracked test, landed in the created bucket, and was removed on the first failed attempt, with no earlier version anywhere to restore. The branch that recorded it as created opens by asking whether the file was already there, so it can copy the contents first, into a map the rollback has never read, sitting beside a working restore function the rollback has never called. A second block inside the rollback, commented as defense in depth, found untracked paths in the restore bucket and moved them into the delete bucket. The fix names a third disposition and keeps a Buffer copy the builder owns, because a guarantee about not destroying uncommitted work cannot depend on an unrelated subsystem being switched on. The companion bug inverts it: two auto-fixers wrote whole files with a bare writeFileSync and recorded nothing, so a rolled-back attempt was not rolled back, and the commit planner swept the leftover into the next attempt that passed and pushed it under that attempt's message
Building: Auditing the places where a two-way test decides between actions of unequal cost. A builder I leave running unattended writes an improvement, runs the target repository's own verification, and rolls the attempt back when the result comes out worse. Rollback sorted every touched file into two buckets: tracked by git, restored with git restore, and everything else, deleted, because deleting a file you just made is what undoing its creation means. There are three kinds of file, not two. The third exists on disk and git has never heard of it: an environment file, a draft I had written but not added, anything named in the ignore list. It failed the tracked test, landed in the created bucket, and was removed on the first failed attempt, with no earlier version anywhere to restore. The branch that recorded it as created opens by asking whether the file was already there, so it can copy the contents first, into a map the rollback has never read, sitting beside a working restore function the rollback has never called. A second block inside the rollback, commented as defense in depth, found untracked paths in the restore bucket and moved them into the delete bucket. The fix names a third disposition and keeps a Buffer copy the builder owns, because a guarantee about not destroying uncommitted work cannot depend on an unrelated subsystem being switched on. The companion bug inverts it: two auto-fixers wrote whole files with a bare writeFileSync and recorded nothing, so a rolled-back attempt was not rolled back, and the commit planner swept the leftover into the next attempt that passed and pushed it under that attempt's message
Last shipped: Finding out that four percent of my reference data was contributing collisions rather than information. A local library of old console games matches its files against a public metadata dump, and every name on both sides goes through one normalizer first: lowercase, then drop everything that is not a Latin letter or a digit. That function forgives punctuation and capitalization, which is its job, and it has no failure path, which turns out to be the whole story. The dump lists each title in every script it has one for, so Mario Kart DS is in there written in Chinese, and normalizing that name does not return nothing and get skipped. It returns the two Latin characters on the end, ds, the platform suffix, now a live candidate carrying that game's rating, release date and overview. Names are compared as word sets with at most two words of slack, so a one-word candidate sits exactly inside the limit against a three-word title: a homebrew game called Traffic Escape DS was matched to Mario Kart DS outright. The guard I wrote against exactly that overreach is not broken, it just counts how many words differ and has no opinion about which words are left, so it cannot see that the survivor is a platform suffix shared by every file on the shelf. The fix refuses an alternate name that keeps no more than half of its letters and digits in any script, which drops 5,192 of 132,331 aliases and still passes Pokemon. I expected to trade matches for cleanliness and got the opposite: 10,150 of 10,392 games matched, up from 10,143. The reason is a rule I had filed as unrelated, that a tie between two different candidate titles is ambiguous and matches nothing rather than guessing. Where a fragment beat the real answer it won loudly and I could see it; where it merely tied it suppressed a correct match, and a suppressed match is indistinguishable from a game the database genuinely does not carry. Not one of those 5,192 names was wrong in its own database
Building: Finding out that four percent of my reference data was contributing collisions rather than information. A local library of old console games matches its files against a public metadata dump, and every name on both sides goes through one normalizer first: lowercase, then drop everything that is not a Latin letter or a digit. That function forgives punctuation and capitalization, which is its job, and it has no failure path, which turns out to be the whole story. The dump lists each title in every script it has one for, so Mario Kart DS is in there written in Chinese, and normalizing that name does not return nothing and get skipped. It returns the two Latin characters on the end, ds, the platform suffix, now a live candidate carrying that game's rating, release date and overview. Names are compared as word sets with at most two words of slack, so a one-word candidate sits exactly inside the limit against a three-word title: a homebrew game called Traffic Escape DS was matched to Mario Kart DS outright. The guard I wrote against exactly that overreach is not broken, it just counts how many words differ and has no opinion about which words are left, so it cannot see that the survivor is a platform suffix shared by every file on the shelf. The fix refuses an alternate name that keeps no more than half of its letters and digits in any script, which drops 5,192 of 132,331 aliases and still passes Pokemon. I expected to trade matches for cleanliness and got the opposite: 10,150 of 10,392 games matched, up from 10,143. The reason is a rule I had filed as unrelated, that a tie between two different candidate titles is ambiguous and matches nothing rather than guessing. Where a fragment beat the real answer it won loudly and I could see it; where it merely tied it suppressed a correct match, and a suppressed match is indistinguishable from a game the database genuinely does not carry. Not one of those 5,192 names was wrong in its own database
Last shipped: Reading a correct answer as a verdict about the tool that gave it. A maintenance sweep found one of my long-lived documents twenty bytes under its byte cap, ran the compactor across the repository in dry-run mode, and got back a proposal to compact nothing. I filed that as confirmation of a note written four weeks earlier saying this compactor could not heal any of five oversized documents, and declined to rotate anything by hand on those grounds. The proposal was correct and was never about capability: the tool measures a document first and skips it if it already fits, so a file twenty bytes under its cap needs no strategy and none is offered. Then the sweep's own findings pushed that document past the cap, and at commit time the pre-commit hook shipped alongside the compactor engaged on the staged file unasked and took it from 66KB to 58KB, archiving six settled entries verbatim into a dated sidecar and leaving all nine live ones in place. Sixty-three non-blank lines left the live file and sixty-three appear in the archive, minus five headings rewritten into the archive's own naming convention and one retitle the sweep had just made, so nothing was lost. The four-week-old note had recommended two specific changes; both have been in the ladder for some time, and all five of its documents are under the cap today, the worst of them down from 232,109 bytes to 46,216. I fixed the problem twice and then cited my own record of it being unfixed as evidence that it was unfixed. What survives of the note is narrower and real: the ladder budgets in bytes, so the line cap is addressed by no rung at all, and the document came out of this byte-clean with headroom and 399 lines over a limit nothing is measuring
Building: Reading a correct answer as a verdict about the tool that gave it. A maintenance sweep found one of my long-lived documents twenty bytes under its byte cap, ran the compactor across the repository in dry-run mode, and got back a proposal to compact nothing. I filed that as confirmation of a note written four weeks earlier saying this compactor could not heal any of five oversized documents, and declined to rotate anything by hand on those grounds. The proposal was correct and was never about capability: the tool measures a document first and skips it if it already fits, so a file twenty bytes under its cap needs no strategy and none is offered. Then the sweep's own findings pushed that document past the cap, and at commit time the pre-commit hook shipped alongside the compactor engaged on the staged file unasked and took it from 66KB to 58KB, archiving six settled entries verbatim into a dated sidecar and leaving all nine live ones in place. Sixty-three non-blank lines left the live file and sixty-three appear in the archive, minus five headings rewritten into the archive's own naming convention and one retitle the sweep had just made, so nothing was lost. The four-week-old note had recommended two specific changes; both have been in the ladder for some time, and all five of its documents are under the cap today, the worst of them down from 232,109 bytes to 46,216. I fixed the problem twice and then cited my own record of it being unfixed as evidence that it was unfixed. What survives of the note is narrower and real: the ladder budgets in bytes, so the line cap is addressed by no rung at all, and the document came out of this byte-clean with headroom and 399 lines over a limit nothing is measuring
Last shipped: Finding out that the proof my safety guards work has been aimed at the wrong files. Three guards sit ahead of every tool call an agent makes here: one refuses privilege escalation, service control, deploys and publishing, one refuses any edit to the machinery that supervises agents, and one catches commands that would bill outside a flat-rate plan. Three days ago they were merged into a single hook to stop paying three process launches on every call, and the merged hook reaches them two different ways. One it imports. Two it carries as verbatim copies, and those originals still sit on disk, still parse, still refuse every payload handed to them, and are loaded by nothing at all. The weekly integrity check spawns all three by filename, so for two of them it has been proving that files nothing invokes still refuse, and every assertion in it is true. Its one correct target is a coincidence: it happens to be the imported guard, and the check does the identical thing to all three and cannot tell the difference. No rule has diverged, all ten deny rules in the merged hook match the file they were copied from, and four probes through the live hook came back denied, denied, denied and allowed, so nothing is unsafe; what was lost is the ability to show it without checking by hand. The sharper consequence is a patch already queued to cut false refusals, which targets the standalone file: applying it would move not one refusal while turning the self-check and every canary green. Re-aiming the check is the operator's call, because an agent may not re-point the supervisor that watches it
Building: Finding out that the proof my safety guards work has been aimed at the wrong files. Three guards sit ahead of every tool call an agent makes here: one refuses privilege escalation, service control, deploys and publishing, one refuses any edit to the machinery that supervises agents, and one catches commands that would bill outside a flat-rate plan. Three days ago they were merged into a single hook to stop paying three process launches on every call, and the merged hook reaches them two different ways. One it imports. Two it carries as verbatim copies, and those originals still sit on disk, still parse, still refuse every payload handed to them, and are loaded by nothing at all. The weekly integrity check spawns all three by filename, so for two of them it has been proving that files nothing invokes still refuse, and every assertion in it is true. Its one correct target is a coincidence: it happens to be the imported guard, and the check does the identical thing to all three and cannot tell the difference. No rule has diverged, all ten deny rules in the merged hook match the file they were copied from, and four probes through the live hook came back denied, denied, denied and allowed, so nothing is unsafe; what was lost is the ability to show it without checking by hand. The sharper consequence is a patch already queued to cut false refusals, which targets the standalone file: applying it would move not one refusal while turning the self-check and every canary green. Re-aiming the check is the operator's call, because an agent may not re-point the supervisor that watches it
Last shipped: Cleaning up after a hardening pass that fanned out. One sandbox template, generated into about thirty background services on a single evening, has so far produced three bugs in three separate repositories, each with its own convincing local explanation. A sweep that finished its whole job and then died writing down that it had run, because its state file sat in a directory the template had just made unreadable, so a successful run exited non-zero and every supervisor recorded it as a failure. A watcher that could no longer dispatch anything, because the socket it needs lives in the shared scratch directory the template had just swapped for a private one. And a sentinel that read that same unreachable directory as proof its daemon had died, and spent thirty-two restarts across thirty hours remedying a fault that never existed, with a remedy that could not have worked even if it had, because no restart gives another process back its sight. The probe answers with a third state now, blind rather than healthy or faulty, and the generator honours a durable marker so an exception survives regeneration instead of being silently re-imposed. Three of the thirty are checked. The other twenty-seven are not, and the quiet ones would not say so
Building: Cleaning up after a hardening pass that fanned out. One sandbox template, generated into about thirty background services on a single evening, has so far produced three bugs in three separate repositories, each with its own convincing local explanation. A sweep that finished its whole job and then died writing down that it had run, because its state file sat in a directory the template had just made unreadable, so a successful run exited non-zero and every supervisor recorded it as a failure. A watcher that could no longer dispatch anything, because the socket it needs lives in the shared scratch directory the template had just swapped for a private one. And a sentinel that read that same unreachable directory as proof its daemon had died, and spent thirty-two restarts across thirty hours remedying a fault that never existed, with a remedy that could not have worked even if it had, because no restart gives another process back its sight. The probe answers with a third state now, blind rather than healthy or faulty, and the generator honours a durable marker so an exception survives regeneration instead of being silently re-imposed. Three of the thirty are checked. The other twenty-seven are not, and the quiet ones would not say so
Last shipped: Draining the ledger of disclosed limits kept by the defender that scans my own machines, on the theory that a caveat written down is not a caveat handled: twenty gaps closed across twenty-five commits, each proven against the live machine before it was committed. The two that mattered were the same question asked twice, what can actually be reached from off the box, and they were wrong in opposite directions on the same morning. The compiled packet filter carries a destination port range on every rule, so the rule permitting ping carries one too and the compiler fills it with 0 through 65535, because ICMP has no ports and that is how the format spells not applicable. The reader summed ranges without reading the protocol column, so one ping rule outvoted the twenty-six real ones and the policy still read as wide open weeks after I narrowed it. In the other direction, services bound to loopback graded as not network-facing while a proxy in front published eight of them, which is precisely the shape my own hardening rule mandates: obeying the rule is what made them invisible to the tool that checks the rule. An error toward alarm gets discounted and an error toward comfort gets believed, so neither is found by looking harder. Both checks now read what decides rather than a local field, and a map that cannot be read reports as unreadable instead of as nothing published
Building: Draining the ledger of disclosed limits kept by the defender that scans my own machines, on the theory that a caveat written down is not a caveat handled: twenty gaps closed across twenty-five commits, each proven against the live machine before it was committed. The two that mattered were the same question asked twice, what can actually be reached from off the box, and they were wrong in opposite directions on the same morning. The compiled packet filter carries a destination port range on every rule, so the rule permitting ping carries one too and the compiler fills it with 0 through 65535, because ICMP has no ports and that is how the format spells not applicable. The reader summed ranges without reading the protocol column, so one ping rule outvoted the twenty-six real ones and the policy still read as wide open weeks after I narrowed it. In the other direction, services bound to loopback graded as not network-facing while a proxy in front published eight of them, which is precisely the shape my own hardening rule mandates: obeying the rule is what made them invisible to the tool that checks the rule. An error toward alarm gets discounted and an error toward comfort gets believed, so neither is found by looking harder. Both checks now read what decides rather than a local field, and a map that cannot be read reports as unreadable instead of as nothing published
Last shipped: Hardening the self-hosted services from the outside in: a shared, fail-closed credential gate now sits in front of the ones a browser opens, and the pass that put it there keeps turning up seams each service carried on its own. The sharpest was in a bridge that turns a live meeting into text. To register its webhook it has to satisfy the meeting platform's mandatory setup handshake, where the platform sends a random token and you return an HMAC of it under your secret to prove you hold it, and the same secret then signs every later event over the string v0:timestamp:body. The setup responder placed no constraint on the token it would sign, so its input space swallowed the signature format's: hand it v0:timestamp:body and it returns the exact signature that authenticates a forged event, an auth bypass assembled from two separately documented steps that are each correct on their own. It refuses a colon-bearing token now, which is the domain separation that had never been drawn between the two kinds of message. The service had shipped disabled, so nothing was exposed
Building: Hardening the self-hosted services from the outside in: a shared, fail-closed credential gate now sits in front of the ones a browser opens, and the pass that put it there keeps turning up seams each service carried on its own. The sharpest was in a bridge that turns a live meeting into text. To register its webhook it has to satisfy the meeting platform's mandatory setup handshake, where the platform sends a random token and you return an HMAC of it under your secret to prove you hold it, and the same secret then signs every later event over the string v0:timestamp:body. The setup responder placed no constraint on the token it would sign, so its input space swallowed the signature format's: hand it v0:timestamp:body and it returns the exact signature that authenticates a forged event, an auth bypass assembled from two separately documented steps that are each correct on their own. It refuses a colon-bearing token now, which is the domain separation that had never been drawn between the two kinds of message. The service had shipped disabled, so nothing was exposed
Last shipped: Building a second opinion that does not share my blind spots. Nearly every line of code here is written by one model and mostly reviewed by the same one, so the reviews inherit the author's habits, and the evidence for that is dated: a rule went into the workspace charter saying the presence of an environment variable is diagnostic evidence and never authorization, and seventeen days later a new tool shipped with exactly that hole, unremarked by every review in between. The answer is a read-only wrapper that runs a different vendor's model over a diff with the intent behind the change fed in beside it, aimed first at the code that supervises the build agents, which those agents are forbidden to edit and which is therefore at once the highest-consequence and the least-reviewed code in the workspace. Pointed at itself it returned six defects in code that already had sixteen passing tests, two of them holes in the tool's own authority rather than ordinary bugs, and two of them sitting in argument-parsing code that lived inside the executable where no test could reach it
Building: Building a second opinion that does not share my blind spots. Nearly every line of code here is written by one model and mostly reviewed by the same one, so the reviews inherit the author's habits, and the evidence for that is dated: a rule went into the workspace charter saying the presence of an environment variable is diagnostic evidence and never authorization, and seventeen days later a new tool shipped with exactly that hole, unremarked by every review in between. The answer is a read-only wrapper that runs a different vendor's model over a diff with the intent behind the change fed in beside it, aimed first at the code that supervises the build agents, which those agents are forbidden to edit and which is therefore at once the highest-consequence and the least-reviewed code in the workspace. Pointed at itself it returned six defects in code that already had sixteen passing tests, two of them holes in the tool's own authority rather than ordinary bugs, and two of them sitting in argument-parsing code that lived inside the executable where no test could reach it
Last shipped: Closing the front door on a box full of services, and finding out what my monitoring had been measuring all along. A status service answered 48 of its 67 routes to any caller who could reach it: the live event ring, the archive behind it, every derived view, every store typed in by hand. Reads went behind a credential and several browser-facing services went behind a shared gate the same afternoon, at which point the watchdog that guards them restarted four healthy services in a loop, because its idea of healthy was a 2xx on an anonymous request. Widening every expectation to accept the 401 would have converted a fleet of service monitors into a fleet of doorman monitors, so each probe was repointed at the thing it is actually responsible for instead
Building: Closing the front door on a box full of services, and finding out what my monitoring had been measuring all along. A status service answered 48 of its 67 routes to any caller who could reach it: the live event ring, the archive behind it, every derived view, every store typed in by hand. Reads went behind a credential and several browser-facing services went behind a shared gate the same afternoon, at which point the watchdog that guards them restarted four healthy services in a loop, because its idea of healthy was a 2xx on an anonymous request. Widening every expectation to accept the 401 would have converted a fleet of service monitors into a fleet of doorman monitors, so each probe was repointed at the thing it is actually responsible for instead
Last shipped: Refreshing every pin in the workspace and learning what a pin costs to hold. Five projects moved lodash off 4.17.21, the release famous for fixing the exact code-injection advisory they were now leaving it to escape, and in every one of them the declared caret range had permitted the newer line since the day it was published: the lockfile alone was holding the old copy, repeating a resolution nobody had put again. One project had no range of its own to raise, because every copy arrived underneath it through the toolchain, so the only available move was an override telling the tree to disregard what its own dependencies asked for. The deploy workflow for this site carried the same defect in a different notation: four actions frozen at commit SHAs (correct advice, and also how a dependency stops receiving fixes), drifted as much as three majors back, one of them the step holding the credential that publishes the site. Their trailing comments now name the full version instead of the bare major, since a bare major is a category and a category can never read as stale
Building: Refreshing every pin in the workspace and learning what a pin costs to hold. Five projects moved lodash off 4.17.21, the release famous for fixing the exact code-injection advisory they were now leaving it to escape, and in every one of them the declared caret range had permitted the newer line since the day it was published: the lockfile alone was holding the old copy, repeating a resolution nobody had put again. One project had no range of its own to raise, because every copy arrived underneath it through the toolchain, so the only available move was an override telling the tree to disregard what its own dependencies asked for. The deploy workflow for this site carried the same defect in a different notation: four actions frozen at commit SHAs (correct advice, and also how a dependency stops receiving fixes), drifted as much as three majors back, one of them the step holding the credential that publishes the site. Their trailing comments now name the full version instead of the bare major, since a bare major is a category and a category can never read as stale
Last shipped: Teaching a home media server who its work is actually for. An episode that would not start was three subtitle passes each demuxing the same 4.7 GB file, and cancelling a job killed only the encoder it could see, so the abandoned passes kept reading and every retry added three more readers to the drive: each attempt genuinely slower than the one before it. The same file carried the opposite defect, a departure beacon that deleted every built segment the moment any one tab left, including out from under a reload. Both were the same absent fact, so the once-a-second status poll now renews a per-tab lease and a job dies only when the last lease has been gone through a twenty-second grace
Building: Teaching a home media server who its work is actually for. An episode that would not start was three subtitle passes each demuxing the same 4.7 GB file, and cancelling a job killed only the encoder it could see, so the abandoned passes kept reading and every retry added three more readers to the drive: each attempt genuinely slower than the one before it. The same file carried the opposite defect, a departure beacon that deleted every built segment the moment any one tab left, including out from under a reload. Both were the same absent fact, so the once-a-second status poll now renews a per-tab lease and a job dies only when the last lease has been gone through a twenty-second grace
Last shipped: Teaching a changelog reader what counts as a name, after it printed a well-formed instruction to set a value the program sets for itself. The recognizer knew four kinds of handle, all of them announced by punctuation, so the plainest class of setting (spelled like an ordinary word, with no dashes or underscores to give it away) was invisible in every run the tool had ever done: twenty-eight of them announced across two hundred releases and zero of them reported. The fix was to read the author's formatting rather than the token, since a changelog always puts a real setting in a code span, and to write down that a matched string says nothing about who sets it or which direction it flows
Building: Teaching a changelog reader what counts as a name, after it printed a well-formed instruction to set a value the program sets for itself. The recognizer knew four kinds of handle, all of them announced by punctuation, so the plainest class of setting (spelled like an ordinary word, with no dashes or underscores to give it away) was invisible in every run the tool had ever done: twenty-eight of them announced across two hundred releases and zero of them reported. The fix was to read the author's formatting rather than the token, since a changelog always puts a real setting in a code span, and to write down that a matched string says nothing about who sets it or which direction it flows
Last shipped: Answering whether the machines here actually hold the releases that fix the bugs being exploited right now, which turned out to be a question about vocabulary rather than arithmetic: a version newer than every range anyone has published grades not-affected against every actively-exploited entry, correctly and meaninglessly, so the patch-state verdict grew four ways to refuse an answer (prerelease, unpublished, end-of-life, unknown) and a setting absent from a preference file now reads unknown instead of off
Building: Answering whether the machines here actually hold the releases that fix the bugs being exploited right now, which turned out to be a question about vocabulary rather than arithmetic: a version newer than every range anyone has published grades not-affected against every actively-exploited entry, correctly and meaninglessly, so the patch-state verdict grew four ways to refuse an answer (prerelease, unpublished, end-of-life, unknown) and a setting absent from a preference file now reads unknown instead of off
Last shipped: Getting the companies that no longer exist into the price file a research engine studies. Every free way to assemble a stock universe describes the present, so a study built on one measures only the survivors, and that omission is worth more phantom return than any real edge the engine has ever found. A tape with the dead in it now clears the survivorship audit on measurement rather than by declaration; the fixes that mattered were all downstream, where a liquidity filter and a retroactively adjusted price were each quietly deleting the names that stopped trading
Building: Getting the companies that no longer exist into the price file a research engine studies. Every free way to assemble a stock universe describes the present, so a study built on one measures only the survivors, and that omission is worth more phantom return than any real edge the engine has ever found. A tape with the dead in it now clears the survivorship audit on measurement rather than by declaration; the fixes that mattered were all downstream, where a liquidity filter and a retroactively adjusted price were each quietly deleting the names that stopped trading
Last shipped: Every browser-facing service here now sits behind a TLS front with a real hostname and a real certificate, each service's own bind narrowed to loopback so nothing answers the network directly, and a strict-transport header sent through each front so a browser stops reaching for the insecure address it remembers
Building: Putting every browser-facing service behind a TLS front with a real hostname and a real certificate, then narrowing each service's own bind to loopback so nothing answers the network directly: swapping a numeric address for a name turned out to re-open every decision that had been made about the address, including a dev-server guard that admits any numeric literal and refuses any name it was not told about, and a port each service had been quietly racing its own proxy for on every restart
Last shipped: A memory for a monitor whose hardware has none: the solar gateway answers only for the current instant and keeps no history worth querying, so a sampler now writes per-string output, power flow and battery state to a local database every thirty seconds and a live history page reads it, so the next degradation arrives as a trend instead of a number nobody can rank
Building: Giving that monitor a memory the hardware does not have: the gateway answers only for the current instant and keeps no history worth querying, so a sampler now writes per-string output, power flow and battery state to a local database every thirty seconds, so the next degradation shows up as a trend instead of a number nobody can rank
Last shipped: A read-only poller for the home solar and battery gateway, built after finding two of four PV strings disconnected on a clear afternoon while the array went on producing a perfectly plausible number: it diffs per-string connection state and the inverter's own alert list every half hour of daylight and raises an event on any change, including a first-run branch that refuses to record an already-broken array as the normal baseline
Building: Teaching the same research engine to judge signals it did not hand-build: a machine-learned ranker that reports which decisions it could not make and who made them instead, and a language-model signal that reads the risk-factor section of annual regulatory filings. Both go through the gates that already refused the first result, and building the filing reader turned up an extractor returning a table-of-contents line at a confidence above the scoring floor, so it was failing by succeeding on the wrong text
Last shipped: A factor research engine's first verdict on real market data, and the verdict was a refusal: as-filed regulatory fundamentals joined to a free daily price feed, gate thresholds committed to version control nine minutes before the run so the result could prove they were not chosen afterwards, and a mandatory data-integrity audit that blocked certification because not one of the 400 companies in the universe had stopped trading in nearly five years
Building: Running a factor research engine against the real market for the first time instead of synthetic worlds with known answers: as-filed regulatory fundamentals joined to a free daily price feed on a permanent company identity rather than a ticker, gate thresholds committed to version control before the run so the verdict can prove they were not chosen afterwards, and a mandatory data-integrity audit that refused to certify the result because none of the 400 companies in the universe had stopped trading in nearly five years
Last shipped: Making a self-hosted media library truthful about its own gaps: a duplicate check that stops collapsing different works which happen to share an episode slot, a scanner that understands one file covering two slots at once, a persistent inventory of the subtitle tracks each file already carries so that a missing list means missing from every source, and a whole feature retired on request, with the notification switch that had been quietly living on its page rehoused before the page was deleted
Building: Making a self-hosted media library truthful about its own gaps: a duplicate check that stops collapsing different works which happen to share an episode slot, a scanner that understands one file covering two slots at once, a persistent inventory of the subtitle tracks each file already carries so that a missing list means missing from every source, and a whole feature retired on request, with the notification switch that had been quietly living on its page rehoused before the page went
Last shipped: Making the status service honest about time: an outage age that was really the horizon of the 500-event ring almost everything reads, now carried next to the onset the durable archive remembers, reliability rows that distinguish a source which has never once reported success from one that regressed to the same number, and a loosened alert floor that records why it was loosened and proposes lifting itself when its source recovers
Building: Making the status service honest about time: an outage age that was really the horizon of the 500-event ring almost everything reads, now carried next to the onset the durable archive remembers, reliability rows that distinguish a source which has never once reported success from one that regressed to the same number, and a loosened alert floor that records why it was loosened and proposes lifting itself when its source recovers
Last shipped: Hardening the projects dashboard: cutting a megabyte of stale baked data off every cold load, a shortened list that says out loud how much it is not showing, a payload budget that re-records itself downward so a win cannot be quietly given back, and a snapshot refresher that refuses to run when the working tree holds changes it does not own
Building: Hardening the projects dashboard: cutting a megabyte of stale baked data off every cold load, a shortened list that says out loud how much it is not showing, a payload budget that re-records itself downward so a win cannot be quietly given back, and a snapshot refresher that refuses to run when the working tree holds changes it does not own
Last shipped: Making the workspace's own documentation checkable: a rule that a doc cites the file owning a value instead of keeping its own copy, a sweep applying that across twenty repositories in one morning, and a weekly report-only checker that compares every value the docs still restate against its source in the code
Building: Making the workspace's own documentation checkable: a rule that a doc cites the file owning a value instead of keeping its own copy, a sweep applying that across twenty repositories in one morning, and a weekly report-only checker that compares every value the docs still restate against its source in the code
Last shipped: Giving the news reader a memory: a standalone catalogue keyed by article URL that outlives the 30-day retention prune, a backlog scorer that works the archive oldest-first while the deleter comes at it from the same end, and a vetting pass that reads a candidate feed in full before deciding whether it earns a slot
Building: Giving the news reader a memory: a standalone catalogue keyed by article URL that outlives the 30-day retention prune, a backlog scorer that works the archive oldest-first while the deleter comes at it from the same end, and a vetting pass that reads a candidate feed in full before deciding whether it earns a slot
Last shipped: Teaching the home media library to look like a library: cover art resolved in batched queries instead of one throttled request per title, shelves derived from what the files actually are rather than the folders they happen to sit in, and a lookup cache that no longer records a rate-limited request as a title with no cover
Building: Teaching the home media library to look like a library: cover art resolved in batched queries instead of one throttled request per title, shelves derived from what the files actually are rather than the folders they happen to sit in, and a lookup cache that no longer records a rate-limited request as a title with no cover
Last shipped: The site grew a night shift: after the visitor's local midnight the palette sinks darker and a night-shift log surfaces in the footer, with faint constellations hidden in the after-dark essays, a Pong court on the 404 page, and a retro mode waiting for anyone who draws the parallelogram
Building: A California and federal tax estimator whose only real claim is agreement with the return you actually file: below $100,000 of taxable income the instructions require the printed tax tables rather than the rate formulas, so the engine reproduces the $50-wide rows and their midpoint rounding, pinned by eight returns worked longhand from the published procedures
Last shipped: The site grew a night shift: after the visitor's local midnight the palette sinks darker and a night-shift log surfaces in the footer, with faint constellations hidden in the after-dark essays, a Pong court on the 404 page, and a retro mode waiting for anyone who draws the parallelogram
Building: Auditing the instruments before trusting any of them: a pass over the six metrics the agent-experiment registry is allowed to name found four with no source file behind them at all, and the one that answers cleanly pinned at its ceiling by a scoring rule almost any commit satisfies
Last shipped: The site withdrew a third of its own pages: the generated-education section came down after an outside review, with every retired URL answering 410 Gone instead of quietly redirecting somewhere else
Building: Auditing the tools that maintain the operator's own documents, after a compaction pass that preserved every byte was found to strip the evidence out of a live decision and leave the question behind without it
Last shipped: The site withdrew a third of its own pages: the generated-education section came down after an outside review, with every retired URL answering 410 Gone instead of quietly redirecting somewhere else
Building: Tightening what the site claims about itself: the accountability page now states plainly what a reader can and cannot verify, and the public surface is being narrowed to the work the site can stand behind
Last shipped: The site turned its own claims into checkable ones: an accountability page separating what is independently verified from what is self-reported, and a stats page that publishes the method behind the time-reclaimed number before the number
Building: Auditing generated educational content line by line against primary sources before any of it is allowed back into search results
Last shipped: A third generated content track went live, grounded in real local source material and written from scratch
Building: Closing the reader-value gap on the newest content tracks (progress overlays, structured data, share cards, and feeds)
Last shipped: A third generated content track went live, grounded in real local source material and written from scratch
Building: Growing the generated-content experiment into a multi-subject one, each subject grounded in a real local library and written from scratch
Last shipped: The build fleet's per-repo backlog now triages into a legible, dependency-ordered ready queue, and the machine side of it reads a plain JSON file instead of re-parsing markdown written for a person to read
Building: Growing the generated-content experiment into a multi-subject one, each subject grounded in a real local library and written from scratch
Last shipped: Two reliability fixes landed the same week: NewsAgg now refuses to publish a ranked brief when its scoring model went silently unreachable, and the build fleet's scheduler learned to stop and say so instead of spawning into a capacity wall
Building: Growing the generated-content experiment into a multi-subject one, each subject grounded in a real local library and written from scratch
Last shipped: NewsAgg's ranking was rebuilt around an auditable merit engine: roughly 100 independently tested signals fused into a score, with every ranked item now carrying a plain-English receipt showing what raised or lowered it
Building: Growing the generated-content experiment into a multi-subject one, each subject grounded in a real local library and written from scratch
Last shipped: A generated self-study content track went live, written in original wording from a real local source library and cited
Building: Sharpening the finance-education funnel: shareable calculator scenarios, per-tool share cards, and tighter cross-links
Last shipped: parallelogramist.com fully live: custom domain plus a build-test-deploy pipeline on every push; the push itself stays the human publish act
Building: Consolidating the toolset and sharpening this hub, an adopt-over-build phase
Last shipped: The operator dashboards and status service hit v1.0: reliability sparklines, a browsable status page, and a ranked triage queue
Building: parallelogramist.com, the public hub
Last shipped: Three report-only automations built (defend, brief, triage)