Full depth — file names, mechanisms, and trade-offs.Concise and competent — what it does, without the internals.Plain language — the value of the work, no jargon.
Lab
What the machine has been building — highlights first, then the full log. Newest first.
Things my automated system has built — the tools and write-ups worth trying first, then the full diary of every step below. Newest first.
★ tools & experiments
Try it
Build the Voice Loop — a browser-only BYO-key spoken loop around Claude that instruments the cascaded latency budget per turn.Voice Loop — a spoken loop around Claude, with the cascade timedVoice Loop — talk to Claude in your browser, and watch where the delay comes from
Built the Voice Loop — a self-contained BYO-key tool at /tools/voice-loop.html that closes a full spoken loop around Claude using only the browser (SpeechRecognition in, speechSynthesis out, no server and no second vendor) and instruments the cascade: speech-end → transcript, transcript → first token, first token → first audio, and the total stop-talking-to-start-speaking, live per turn with a session median. Push-to-talk and continuous turn-taking, barge-in, verbatim transcript alongside the conversation, and explicit copy that the browser's recogniser may ship audio to the browser vendor.Built the Voice Loop: a single-file, bring-your-own-key tool that talks to Claude using only the browser's own speech recognition and speech synthesis — no server, no second vendor, no extra key. The research payload is the stopwatch: every turn is split into the four stages of the cascade, live, with a running session median, so the cost of gluing four systems in a line is something you measure in your own hands. Two turn-taking modes (explicit push-to-talk versus a VAD guess), barge-in, and the raw recogniser output shown next to every turn so mishearings stay visible.Built a tool that lets you talk to Claude out loud in your browser and hear it answer. The real point is the timer: it breaks every exchange into the steps that made it slow — hearing you, thinking, starting to speak — so the lag stops being vague. You can hold a button to talk or leave the mic open, and it always shows what it thought you said so you can catch mishearings. Your Anthropic key stays in your browser, but the page says plainly that the browser's speech recognition may send your voice to the browser maker.
Try it →Build the Branching Canvas Conversation — a BYO-key tool where a chat is laid out spatially on a canvas and any message can be branched into a parallel thread.Branching Canvas Conversation — chat drawn as a tree you can branchBranching Canvas Conversation — a chat you can split into side-by-side threads
Built the Branching Canvas Conversation — a self-contained BYO-key tool at /tools/branching-chat.html that models the chat as a message tree on a hand-rolled pan/zoom canvas, streams from the Anthropic API, and lets you branch off any message into a parallel thread; sending from a node assembles context as the root-to-node path, with a toggle between the canvas and a linear chat view.Built the Branching Canvas Conversation: a single-file, bring-your-own-key tool where every message is a draggable node in a conversation tree on a pan/zoom canvas. Branch off any message into a parallel thread — each reply uses the path from the root down to that node as its context — and toggle to a linear view to read one thread top to bottom.Built a chat tool that draws the conversation as a tree instead of one straight line. Every message is a card on a canvas, and you can split off from any point to try a different direction without losing the first one. There's also a normal top-to-bottom view. You paste your own Anthropic key and it never leaves your browser.
Try it →Build the Memory Inspector tool — a BYO-key chat whose memory store is visible beside it, with per-turn extraction and confidence/sensitivity shading.Memory Inspector — a chat that shows what it remembers about youMemory Inspector — see and edit what a chat assistant remembers about you
Built the Memory Inspector at /tools/memory-inspector.html — a browser-direct BYO-key chat whose extracted memory store sits open beside it, where each entry's background shading encodes inferred confidence and sensitivity, and entries can be edited or forgotten inline.Built Memory Inspector: a bring-your-own-key chat that shows its memory beside it. After each turn Claude extracts durable facts about you, shaded by how sure and how private each is; you can edit or forget them, and changes take effect next turn.Built Memory Inspector: a chat where everything the assistant decides to remember about you shows up in a list next to the conversation, tinted by how sure it is and how private the fact is. You can correct or delete anything, and the next reply uses your corrections. Your Anthropic key never leaves your browser.
Try it →Build the Reasoning-trace A/B — a client-only demo where you judge whether to trust an AI's reasoning trace, some of which reach the right answer through a subtle fabricated or broken step.Reasoning-trace A/B — can you tell a sound trace from a confident wrong one?Reasoning-trace A/B — a quiz on whether an AI's shown work can be trusted
Built the Reasoning-trace A/B — a self-contained, offline tool at /tools/reasoning-trace.html that presents an AI's confident answer plus a reasoning trace and asks the visitor to trust or flag it; half the traces reach the same correct answer through a subtle fabricated fact, invented premise, or broken justification, and the tool tracks how many flaws the visitor caught versus how many fooled them. A reveal-timing toggle (instant / delayed / on-demand) demonstrates the finding from Seeing the Reasoning that presentation barely moves trust while reliability does.Built a client-only tool where an AI shows a question, a confident answer, and a reasoning trace, and the visitor judges whether to trust it. Half the traces are unfaithful — they land on the same correct answer via a subtle flaw (a fabricated latitude, an invented logical premise, a conceptual error, a wrong date). The tool tracks flaws caught versus times fooled, and a reveal-timing toggle demonstrates the research finding that how a trace is shown barely moves trust while whether it is reliable does.Built a quiz where a computer answers a question and shows its work. Sometimes the work is honest; sometimes it reaches the right answer through a step that's quietly wrong. You decide whether to trust it and find out if you were fooled — which is the point researchers made: a confident-looking explanation earns trust whether or not it's actually correct.
Try it →Build the Generative UI Canvas — a BYO-key tool where a typed request makes Claude generate interactive app windows on a canvas, and interacting with a generated app re-invokes the model.Generative UI Canvas — Claude builds app windows on a canvasGenerative UI Canvas — you ask, Claude builds a working little app
Built the Generative UI Canvas — a self-contained BYO-key tool at /tools/generative-ui.html that streams from the Anthropic API, holds three window-manipulation tools for Claude, and renders generated apps in sandboxed iframes on a hand-rolled pan/zoom canvas; interacting with a window posts back and re-invokes the model.Built the Generative UI Canvas: a single-file, bring-your-own-key tool where a typed request makes Claude generate interactive HTML app windows on a pan/zoom canvas. Generated code runs in sandboxed iframes that cannot reach the page or the key; clicking inside a window posts back and re-invokes the model.Built a tool where you type what you want — say a tip calculator — and Claude writes a small working app for it on a canvas. You paste your own Anthropic key and it stays in your browser. The apps Claude writes run in a sealed box that can't read your key, and clicking inside one sends the click back to Claude so it can update the app.
Try it →Research and build a first prototype of a better recipe/cooking tool: a self-contained single-file reader at public/tools/cooking.html targeting the known pain points of cooking from a screen.Cook Mode — a single-file recipe readerCook Mode — a recipe page built for actually cooking
Built Cook Mode — a dependency-free single-file recipe reader with one-step-at-a-time navigation, timers parsed out of the step text, ingredient scaling, unit conversion, and a screen wake lock.Built Cook Mode: a single-file recipe reader with one step at a time, timers pulled out of the step text, ingredient scaling, unit conversion and a screen wake lock.Built Cook Mode: a recipe page designed for cooking from, not for reading. It shows one step at a time, starts timers for you, scales the ingredients up or down, converts between cups and grams, and stops the screen going dark when your hands are covered in flour.
Try it →Reads
Interaction Landscape — 2026-07-20
Surveyed 32 verified LLM interaction patterns across nine areas — generative UI protocols, spatial and direct-manipulation interfaces, agent-initiated pausing, elicitation and memory UX — with a browser-only BYO-key generative UI canvas as the top prototype candidate.
Read →Site Health — week of 2026-07-18Website health check — 18 July 2026
Weekly automated audit of a monitored property: availability, response time, SSL, and link checks all came back clean; the security-header check did not.Weekly automated audit: availability, response time, SSL and links all came back clean. The security-header check did not — the specifics are held privately.The weekly automatic check of a website. Everything was up, fast and correctly encrypted, and no links were broken — but it was missing some standard browser protections, so that was flagged and then fixed.
Read →Agent Weekly — week of 2026-07-18This week in AI agents — 18 July 2026
Agent Weekly, July 11-18 2026: six verified items, led by Moonshot's 2.8T open-weight Kimi K3 and Thinking Machines' first model Inkling; the week's loudest headlines (GPT-5.6, the MCP spec RC) fall outside the window.Six verified items for July 11-18 2026, led by Moonshot's open-weight Kimi K3 and Thinking Machines' first model, Inkling. The week's loudest headlines fall outside the window.A round-up of what actually happened in AI this week, with every item checked against its original source. The biggest headlines you may have seen landed just outside this week's window, so they aren't counted here.
Read →activity log — the routine build cycles
build diary — every step, unedited
35 / 35 entries
Stamp engine dates in the box's local timezone, not UTC
Engine dates now stamp in the box's local timezone instead of UTC, so evening cycles stop dating themselves tomorrow.
Move post-failure recovery inside the single-instance lock
Post-failure git recovery now runs inside the single-instance lock in both runners, closing the window where a second tick could have its untracked files cleaned out.
Build the **App Subdomain** research sprint
Added the App Subdomain one-shot research sprint: a briefing-type experiment that surveys what it would take to host server-side LLM interaction alongside the static Cloudflare deploy, ending in ranked options for Wolf's review.
Give writing posts their own pages and fix the RSS guid collision.…
Writing posts get per-post routes and the RSS feed's writing guid collision is fixed.
Finish wiring the visitor tech-level switch into the routes that still…
Wired the tech-level switch into Home, Work, Writing, Video and Now, and made the work/writing/video summaries level-aware.
Add an in-code single-instance lock to engine/run-cycle.mjs AND…
Added a dependency-free pidfile single-instance lock to both engine runners so overlapping runs can't corrupt each other's git state.
Extract the experiment registry into a module and collapse the wrapper…
Extracted the experiment registry into engine/experiments/registry.mjs and collapsed the three cron wrappers into one parametric engine/run-experiment.sh, with the named scripts kept as backward-compat shims.
Build the **Interaction Lab** standing digest
Added the Interaction Lab standing digest — a monthly recurring experiment that keeps the LLM-interaction landscape fresh after the one-shot sprint.
Build the **Interaction Landscape** research sprint
Added the one-shot Interaction Landscape research sprint — a survey of novel LLM interaction paradigms that renders as a draft briefing for review.
Build a visitor-selectable **tech level** for the whole site. A…
Added a visitor-selectable tech level — technical, tech-aware, or plain — that re-reads the whole site from pre-authored copy variants, switched client-side by CSS with no per-element JavaScript.
Extend loop-skip so it skips a backlog item whose branch has ANY…Loop-skip now counts closed and merged PRs tooClosed the last way the machine could repeat itself
Loop-skip now treats a branch with ANY PR — open, closed, or merged — as already built, so a superseded PR can no longer make the loop rebuild the same item.Any pull request — open, closed or merged — now counts as already built, so a superseded one cannot make the loop rebuild the same item.The machine skipped work it had already submitted, but only while that work was still open. If I closed it, the machine would start again from scratch. Now finished is finished.
Build a Tools home and link Lab entries to their tools. FOUR partsA Tools home, and Lab entries that link to themGave the tools a home page of their own
Added a tools content collection, a /tools listing page, a Tools nav link, and an optional tool field that links Lab entries to the tool they shipped.Added a Tools section and a nav link to it, plus a field that links a Lab entry to the tool it shipped.The tools built here were hard to find. They now have their own page in the menu, and any entry that produced a tool links straight to it.
Revamp the Lab page filter UX (src/components/LabFilter.tsx + its use…Rebuilt the Lab filter UXMade this page easier to search
Replaced the Lab page's per-tag button row with a search box plus tag/type dropdowns, backed by a unit-tested pure filter module.Replaced the growing row of tag buttons with a search box and two dropdowns, backed by a tested filter module.This page had a button for every topic, and there were getting to be far too many. Replaced them with a search box and two simple dropdowns.
De-duplicate the Cook Mode Lab entriesDe-duplicated the Cook Mode entriesCook Mode was listed twice — fixed
Removed the duplicate generic build-log Lab entry for Cook Mode, leaving the single dedicated writeup.Removed the duplicate build-log entry for Cook Mode, leaving the single proper write-up.Cook Mode had accidentally been posted here twice. Removed the duplicate.
Add good-citizen defaults to engine/probes/site-health.mjs so the…Good-citizen defaults for the site proberMade the website checker a polite visitor
Gave the Site Health probe good-citizen defaults — identifying User-Agent, per-origin robots.txt compliance, and a serialising rate limiter — with 25 new unit tests.The site prober now identifies itself, honours robots.txt per origin, and rate-limits its requests. 25 new tests cover the behaviour.The tool that inspects websites now behaves politely: it says who it is, obeys each site's rules about what may be visited, and spaces out its requests so it never hammers anyone's server.
Make the self-building loop skip a backlog item whose branch already…The loop skips items already waiting on reviewThe machine stopped redoing work it had already finished
The loop now skips backlog items whose branch already has an open PR, so an unmerged gated PR no longer parks the cycle on the same item.The loop now skips any backlog item that already has an open pull request, so work waiting on review no longer blocks the queue.When a piece of work was finished but still waiting for my approval, the machine kept picking it up and building it again. Now it moves on to the next thing.
Close the Site Health audit's security-header findingClosed the security-header findingFixed the security gap the checker found
Added public/_headers so Cloudflare serves HSTS, nosniff, SAMEORIGIN, Referrer-Policy and a report-only CSP on all routes, with tests guarding the policy.Added the missing security headers across every route — HSTS, nosniff, frame and referrer policy, plus a report-only CSP — with tests guarding them.The health check had found this site was missing some standard browser protections. Added them, with tests so they cannot quietly disappear again.
Create engine/run-health.sh (mirror engine/run-weekly.shCron wrapper for the health runPut the weekly health check on a schedule
Added engine/run-health.sh cron wrapper for the site-health experiment and documented the Wednesday 07:00 crontab line.Added the cron wrapper for the site-health run and documented its Wednesday 07:00 schedule.Scheduled the website health check to run by itself every Wednesday morning.
Add a per-experiment `kind` (digest|monitor) to…Per-experiment kinds: digest vs monitorTaught the machine two different kinds of job
run-experiment.mjs now dispatches on a per-experiment `kind`, adding a monitor pipeline that probes, judges, archives the private report, and publishes only the sanitized public block.The experiment runner now handles two kinds of job: written digests and automated monitors. A monitor run archives a private report and publishes only the sanitised public version.The machine can now do two different jobs: write a weekly summary of the news, or run a health check on a website. When it runs a health check it keeps the sensitive findings private and publishes only a safe summary.
Write engine/experiments/site-health.mdThe monitor's operating manualWrote the rulebook for the health check
Wrote engine/experiments/site-health.md, the monitor operating manual that turns deterministic probe Findings into a PrivateReport with a fail-closed private/public split.Wrote the monitor's operating manual — how measured findings become a report, with a strict split between private detail and the public summary.Wrote the instructions the machine follows when it checks a website: what to measure, and the strict line between the private details and what may be said in public.
Build engine/probes/site-health.mjs exporting `async probe(target)`…A deterministic site-health probeBuilt the tool that checks a website's health
Built engine/probes/site-health.mjs — a deterministic Node fetch + node:tls site auditor — with 21 unit tests over mocked fetch/tls.Built the site auditor itself — page checks, response times, SSL expiry and link checking — with 21 unit tests.Built the part that actually inspects a website: is every page loading, how fast, is the security certificate about to expire, and are any links broken.
Extract the pure sanitizer logic from src/lib/sanitize.ts into a new…Sanitiser split into a shareable coreLet both halves of the system share one safety filter
Extracted the sanitizer into plain-JS src/lib/sanitize.core.mjs so engine .mjs code can import it; sanitize.ts is now a typed re-export.Split the sanitiser into a plain-JS core the engine can import, with the typed wrapper left in place for the site.The safety filter existed only where the website could use it. Moved it so the machine uses the very same filter — one filter, rather than two that could drift apart.
Make engine/run-experiment.mjs resilient to an existing remote branchSame-day re-runs no longer collideRunning the same job twice in a day no longer breaks it
run-experiment.mjs now steps a same-day re-run to the next free branch name instead of failing on a non-fast-forward push.A same-day re-run now steps to the next free branch name instead of failing on the push.Running the same job twice on one day used to clash with itself and fail. Now the second run gives itself a new name and carries on.
Build the Agent Weekly experimentThe Agent Weekly experiment, end to endSet up the weekly AI news round-up
Built the Agent Weekly experiment: a research-prompt + run-experiment.mjs runner that publishes a weekly type:digest Lab entry via publishBranch.Built Agent Weekly end to end: the research brief plus the runner that publishes the digest to the Lab each week.Set up a job that runs every Sunday: the machine researches the week's AI news, checks its sources, and posts a summary here by itself.
Extract the commit/push/PR/account-restore machinery from…Extracted a reusable publishBranch()Tidied up the publishing step so it is shared, not copied
Extracted the commit/push/PR/account-restore machinery into a reusable publishBranch() in engine/publish.mjs and rewired run-cycle.mjs to call it.Pulled the commit, push and pull-request machinery into one reusable publishBranch() so every job shares it.The steps for saving and submitting finished work were written out twice. Merged them into one, so there is a single thing to fix if it ever breaks.
Add `digest` to the direct-publish policy in engine/lib.mjs so…Digests publish without reviewWeekly summaries now publish on their own
Digest entries now publish direct (draft:false) via the direct-vs-review gate.Digest entries now go straight to the site instead of waiting as drafts.The weekly news summaries now go live on their own, instead of sitting and waiting for me to approve them.
Encode the direct-vs-review gateThe direct-vs-review gateDecided what the machine may publish unsupervised
Encoded the direct-vs-review gate as a pure per-type policy and wired it into the runner's lab-entry render.Turned what may publish itself and what needs review into an explicit per-type policy the runner applies.Wrote down the rule for what the machine may post on its own and what has to wait for me to read first — so it is a rule, not a habit.
Add engine/lib.mjs helper publicEntryFromReport(privateReport) that…One helper for turning a private report publicOne safe route from private notes to a public post
Added publicEntryFromReport() to engine/lib.mjs — sanitizes a private report then renders a public lab entry, failing closed if a secret leaks.Added a single helper that sanitises a private report and renders the public entry, refusing to publish at all if a secret would leak.Everything the machine publishes now goes through one safety check first. If it spots anything private in the text it refuses to publish, rather than risk leaking it.
Make engine/run-cycle.mjs re-runnableThe runner is safely re-runnableThe machine can now recover and try again
Made the lab engine runner re-runnable — reuses an existing lab/<slug> branch and returns to a clean main on any cycle failure.The runner now reuses an existing branch instead of crashing on it, and always returns to a clean state after a failure.If a job failed halfway through, the machine used to get stuck and need me to untangle it. Now it cleans up after itself and can simply start over.
Quote unsafe tags in renderLabEntry (engine/lib.mjs)Quote YAML-unsafe tagsStopped certain tag names breaking the site build
renderLabEntry now quotes numeric and YAML-reserved-word tags so they stay strings.Tags that are numbers or YAML keywords are now quoted, so they stay strings and cannot fail the build.A tag like 2026 or no could be misread by the site builder and break the build. They are now written in a way that cannot be misread.
Harden the sanitizer secret-scan in src/lib/sanitize.ts against…Hardened the secret scan against escapingClosed a gap in the leak filter
Hardened the lab-report sanitizer so secrets containing quotes or backslashes can't evade the leak scan via JSON escaping.Hardened the leak scan so a secret containing quotes or backslashes can no longer slip past it through JSON escaping.Found a way a password containing certain punctuation could have slipped past the leak filter unnoticed. Closed it, and added tests so it stays closed.
Fix currentGhUser() in engine/run-cycle.mjs for gh 2.45: do not use the unsupported `gh auth status --active` flag; instead parse `gh auth status` output for the account marked active. Extract the parsing into a pure helper in engine/lib.mjs and unit-test it against sample gh output.Fixed GitHub account detection on gh 2.45Fixed the machine losing track of which account it uses
Fixed currentGhUser() for gh 2.45 by parsing `gh auth status` instead of using the removed `--active` flag.Fixed account detection against gh 2.45, which had dropped the flag the old code relied on.A tool the machine depends on changed, and it stopped being able to tell which account it was signed in as. Fixed.
Add an independent verify gate to engine/run-cycle.mjs: after the machine cycle, the runner itself runs `npm test` and `npm run check`; if either fails, override the cycle-report status to `flagged` and prefix the PR title with `[FLAGGED]`. Extract a pure `resolveStatus(reportStatus, testsPassed, checkPassed)` helper into engine/lib.mjs and unit-test it in engine/lib.test.mjs.An independent verify gate on every cycleThe machine now double-checks its own work
The runner now independently re-runs npm test and npm run check after each cycle and flags work that fails.After each build the runner re-runs the test suite itself rather than trusting the report it was handed, and flags anything that fails.After the machine finishes a piece of work it tests the result itself, instead of taking its own word for it. Anything that fails gets flagged for me to look at.
Build the sanitization filter — implement `src/lib/sanitize.ts` so `npm test` passes (allowlist + fail-closed; do not weaken the seeded tests)The sanitisation filterBuilt the filter that keeps private things private
Implemented the allowlist + fail-closed sanitizer so lab reports emit only curated public fields and never leak registered secrets.Implemented the sanitiser: only explicitly allowed fields reach a public entry, and anything unexpected blocks the publish.Built the filter that decides what is safe to publish. Only things on an approved list get through, and if anything looks like a secret the machine stops rather than publishing it.
The lab is live
First entry. The site scaffold is up — Astro + Tailwind, paper theme, and this running log.First entry. The site is up — Astro and Tailwind, the paper theme, and this running log.The first entry. The site exists, it looks the way I wanted, and this running log is now open.