Nov 2025 – present · softwaresoftware.dev

Nine months of work, 268 pieces of content

Every idea below is anchored to something on the workstation — a repo, a commit, a benchmark result, a memory note. Seeded with 100 on Aug 15, 2026; a nightly pass over each day's commits adds to the log at the top. Formats are mixed on purpose: long-form for the architecture stories, charts and 60-second cuts for the numbers, gifs for anything with a live URL.

268ideas · updated 2026-10-14
2,925commits, 150 repos
46%co-authored with Claude (57% since March)
45marketplace plugins, 26 capabilities
18research posts in ten days
34archived projects (37%)
Format Effort 268 of 268

Daily log · 168 added since Aug 15

What the last few days produced

A nightly pass reads the day's commits and memory notes and proposes new pieces here. Newest first. Everything below the log is the original seed of 100.

  1. 001
    Blog postMedium · 2–3 daysadded 2026-10-14

    The agent proposes the term change; an underwriter approves it

    Crestborne's deal agent can now change the underwriting case and scenarios recompute downstream, but changes to loan terms sit as a 'Proposed' card until a human approves or dismisses. Explain why scenarios auto-follow while terms are gated, and why the agent's message leads with the word 'Proposed'.

    apps/crestborne-staging commits 7267374, d9e6598, debc979
  2. 002
    ThreadSmall · a dayadded 2026-10-14

    A Review tab built around the terms the agent moves

    Instead of a diff of agent actions, the Review tab groups changes by the underwriting term they affect. Walk through the design choice: reviewers care about 'DSCR moved from X to Y', not 'agent edited field 14'.

    apps/crestborne-staging commit debc979 (11 files, +517/-59)
  3. 003
    Blog postMedium · 2–3 daysadded 2026-10-14

    A broker's spreadsheet became rules: merging Wessel's checklists into the document menus

    A domain expert's workflow sheet had triggers ('check whether these apply') that became code rules in the document menus. Cover the cleanup of sheet artefacts like 'OVERKILL??' and stripped source refs, and what it takes to turn a human checklist into a trigger engine.

    apps/crestborne-wessel commits 1bb2170, 069c75d, a3ffb00 (+1050/-146 in the merge)
  4. 004
    Blog postMedium · 2–3 daysadded 2026-10-14

    Spoofing rings: detecting GPS crop-circle spoofing in raw ping data

    geolab added detection of GPS crop-circle spoofing, where devices trace circles at fake positions. Show the detector, a per-location satellite map, and the report-section fix for a 1fr grid tile overflowing coordinates.

    apps/geolab commits 1d8f8d1 (+1092), 3f58620, 9b7767d
  5. 005
    ThreadSmall · a dayadded 2026-10-14

    Splitting a zone along roads needed always_xy

    Road-aware zone splitting in geolab broke because the coordinate transform assumed a different axis order from the data. Tell the lat/lon vs lon/lat story and the always_xy fix, as a pyproj gotcha.

    apps/geolab commit 11a6f52
  6. 006
    Blog postMedium · 2–3 daysadded 2026-10-14

    Nested spaces to any depth, each with its own channels

    The platform POC went from flat workspaces to arbitrarily nested spaces, with per-space channels, per-workspace file storage with trash, and hourly backups, all in one day. Cover the data-model decisions and what broke across 61 files.

    apps/platform commits 1f50b6f (+1598/-600), 9813924 (+2344/-412)
  7. 007
    Blog postMedium · 2–3 daysadded 2026-10-13

    20,875 lines in, 6,730 out: porting a Python-rendered UI to a React SPA in one commit

    The platform's app.py stopped rendering HTML and became a JSON API while the UI moved to React + shadcn/ui + AI Elements. Cover what had to change on the server, what the 258-file diff looked like, and why a rewrite this size was safe in a day.

    apps/platform commit 170e881 (258 files, +20,875/-6,730)
  8. 008
    Blog postMedium · 2–3 daysadded 2026-10-13

    Streaming a Claude Code session into a browser chat: tools, diffs, thinking, stop button

    The platform mirrors a real node session as chat. Turn the transcript into messages.json, stream turns with tool calls, diffs and a thinking timer, and fix two bugs: idle sessions shouldn't run a live timer, and thinking spans must end at the next block.

    apps/platform commits 38e04fb, 06cfb53, a7878df
  9. 009
    ThreadSmall · a dayadded 2026-10-13 posted to X · 2026-10-14

    Bring your own agent: the connector key is a shell on your box, so agents are never shared

    Design decision: per-user connector keys, private agent chat, and no sharing of agents inside a workspace. Explain why sharing an agent would mean sharing a shell, and how the one-command installer fixed the connector's PATH under launchd/systemd.

    apps/platform commits b386cfa, d34e3a9, 609af26
  10. 010
    Blog postMedium · 2–3 daysadded 2026-10-13

    A knowledge base where the agent only sees excerpts from the poster's own notes

    The KB rework added per-person personal tiers, ranked search, and KB context for agents. The follow-up commit then restricted agent excerpts to the poster's own notes and made repo-backed tiers owner-write only. Explain the leak the first version allowed.

    apps/platform commits be9da62, c0f0b87
  11. 011
    ThreadSmall · a dayadded 2026-10-13 posted to X · 2026-10-14

    Making a Python web app installable: service worker, manifest, VAPID, per-user push

    Walk through adding web push to the platform in one commit: manifest, service worker, VAPID keys, per-user subscriptions. Cover what breaks when subscriptions are scoped to accounts instead of one owner.

    apps/platform commit 98b9f50 (66 files, +2,042)
  12. 012
    Blog postMedium · 2–3 daysadded 2026-10-12

    A trip-planning site with an AI terminal that edits the site itself

    cr-concierge is a sandboxed taskpilot agent behind the cr.softwaresoftware.dev terminal. Travelers ask for changes, and the agent researches, edits, builds, screenshots and checks the site, then commits it with an '(asked by Sarah)' attribution. The post covers the dev helpers (shot, fetch-image, build, check), the 15-minute job cap, and why a revert of the chocolate-tour commit was one command.

    apps/cr-trip (c3f8f03, e4ce0b5); staticsites/cr.softwaresoftware.dev commits b3c2df6, 21e4e51, fce8f3b
  13. 013
    ThreadSmall · a dayadded 2026-10-12 posted to X · 2026-10-13

    Every edit your travel companions ask for becomes a commit with their name on it

    The commit log of cr.softwaresoftware.dev reads as a change history of the trip: swap Manuel Antonio for Playa Hermosa, add 3 stays, fix the routes and pins afterward, revert a tour. Show how attributing each agent edit to the requester makes undo and blame useful for non-developers.

    staticsites commits fce8f3b, 025795d, 9ad59a5, fac5f61, fd44401, b6d25f9/21e4e51
  14. 014
    Blog postMedium · 2–3 daysadded 2026-10-12

    Stats from a site that blocks curl: fetching tracker.gg through your own browser tab

    api.tracker.gg returns 'You've Been Blocked' to plain curl, so r6watch runs its fetches inside a real Brave tab via the browser-bridge socket. A 429 inside the page shows up as 'TypeError: Failed to fetch', so the backoff is 20/60/180s. Matches are keyed by id and merged across players, so shared squad games appear once.

    tools/calwatch/r6watch (84d7c70); staticsites/r6.softwaresoftware.dev (df05122)
  15. 015
    Blog postMedium · 2–3 daysadded 2026-10-12

    A progress bar wasn't enough: what a 3-minute report job has to show

    Thatcher's no-micro-copy rule held for static state but failed for long jobs ('I can't tell if its broken'). geolab's investigation reports now show the current step with i/n, a checklist with durations, elapsed time and a heartbeat with a stale warning. The post argues static state belongs in affordance and live work belongs in telemetry.

    apps/geolab a022ad6; memory feedback_no_ui_state_labels
  16. 016
    Blog postSmall · a dayadded 2026-10-12

    Packs derived from the data instead of a hardcoded taxonomy

    Splitting 10,338 LOIs into ~138 packs uses one SQL grouping expression shared by both the count and the membership filter, so they cannot drift. The packs round-trip to exactly 10,338. The post covers GROUP_FIELD per source and the collapse depth that reaches the service branch.

    apps/geolab packs.py (f7ea4d8); memory project_geolab_loi_packs
  17. 017
    Blog postMedium · 2–3 daysadded 2026-10-09

    Nine MCP servers, nine copies per session: moving to one shared HTTP process

    Each Claude session spawned its own stdio copy of every user-scope MCP, roughly 1 GB per session and about 9 GB with nine sessions. Taskpilot agents and claude -p runners each spawned all 11 servers. The fix was a --http streamable mode in each server plus one mcp-shared@<name> systemd unit per server on ports 9021-9029. Covers what had to change: tools run off the event loop, a registry save lock, and the mesh 404 re-init.

    mcps/gdrive-mcp bc33c12, mcps/google-calendar-mcp 38f53bd, mcps/google-contacts-mcp 5e9b859, mcps/finance-mcp 94c154b, tools/session-bridge c2f1977, tools/conduit 810a095; memory/project_mcp_shared.md
  18. 018
    ThreadSmall · a dayadded 2026-10-09 posted to X · 2026-10-12

    The RAM crush wasn't Claude, it was the MCP fan-out

    Diagnosis story: memory pressure was blamed on claude itself, but every headless runner launched all 11 MCP servers. Count the processes, multiply by per-server RSS, and the cost is obvious. Ends with the one-process-per-server fix and the rule to never re-add them as stdio.

    memory/project_mcp_shared.md; mcps/slack-mcp 9d2e48d
  19. 019
    Blog postSmall · a dayadded 2026-10-09

    The trust dialog flipped to 'No, exit' and blind Enter started killing sessions

    Claude Code's startup trust dialog now defaults to 'No, exit', so a script that presses Enter blindly kills the session. Taskpilot now selects the answer by its label, and uses --channels when the plugin is allowlisted in managed settings. One remaining spawner (home-taskboard respawn) still has the old blind-Enter bug.

    plugins/providers/taskpilot 5f6b3e4; memory/project_mcp_shared.md
  20. 020
    Blog postSmall · a dayadded 2026-10-09

    A chat id that repeats after a reseed will show you the wrong transcript

    The deal-agent page tails a session transcript to render a live step feed. After a database reseed, chat ids repeat, so the page matched a stale session from before the question. The fix refuses to read any session older than the question. A general rule for joining on ids that get reused.

    apps/crestborne-staging b9d06af, f53463b
  21. 021
    Blog postMedium · 2–3 daysadded 2026-10-09

    Hold the assistant's write calls for approval

    Apollo's assistant now pauses its write tool calls until the user approves them, while reads run freely. Covers where the hold sits in the job flow, the job-name readability changes in the same commit, and why campaign candidates fold on phones.

    apps/apollo b2ac75f
  22. 022
    Short (60s)Small · a dayadded 2026-10-09

    OSM tiles stopped loading until we sent the origin as referer

    Cross-site tile requests came back blocked because the default referrer policy stripped the path and the origin was not sent. A two-file fix sends the origin as the referer cross-site. A short note on tile-server usage policies and referrer policy.

    apps/apollo de485be
  23. 023
    Blog postSmall · a dayadded 2026-10-08

    Every uploaded document spawns a reader agent, and flow-check spawned twenty of them

    Since 9c9bde3 each filed document is read by an agent into the deal file. Deep flow-check across 10 flows then launched ~20 real ~2.2 GB agents on top of the 10 flow agents, pushed swap to 100% and memguard to CRIT. Per-document fan-out makes agent count grow with every test flow, so the fix was to default to fast mode and run only flow 02 deep.

    apps/crestborne commit 9c9bde3; memory/feedback_flowcheck_deep_memory.md
  24. 024
    Blog postSmall · a dayadded 2026-10-08

    Park the feature, keep the code: hardening Crestborne for production behind flags

    7a43d98 'harden for production; park document reads' plus a13c356 (CRESTBORNE_SHOW_SPONSOR_EXPOSURE) show the pattern of shipping a prod promote with risky features switched off by env flag instead of being deleted. Covers what got parked, what the flag default is, and why prod got its own agent token.

    apps/crestborne commits 7a43d98, a13c356, c888a0c
  25. 025
    ThreadSmall · a dayadded 2026-10-08 posted to X · 2026-10-11

    Four security headers added in 17 lines before a public promote

    c888a0c adds no third-party framing, nosniff, same-origin referrer, and HSTS only on the public host. HSTS is scoped to the public host so tailnet/staging access doesn't get pinned to HTTPS. Short walkthrough of each header and what it blocks.

    apps/crestborne commit c888a0c
  26. 026
    Blog postMedium · 2–3 daysadded 2026-10-08

    Send only the fields you agreed on: gating an insurer API payload to a written list

    8f6926a restricts INSTANDA/Kuma calls to the fields agreed with the vendor on 2026-09-24 and rates once at sign-off. Earlier e85bc16 moved binding from approval to funding. Both narrow when and what leaves the system to an external policy API; a dry-run mock that answers whole (9c9bde3) keeps testing possible.

    apps/crestborne-staging commits 8f6926a, e85bc16, 5874ad5
  27. 027
    Blog postMedium · 2–3 daysadded 2026-10-08

    An in-app document viewer in one commit: PDF.js, Office via PDF, no downloads

    934400a (332 insertions, 13 files) renders PDFs page by page with PDF.js, converts Office files to PDF, and shows images and text inline so a reviewer never downloads a file to look at it. Follow-up 44f1168 had to open the viewer route to partner roles because it was gated differently from the download route.

    apps/crestborne commit 934400a, staging 44f1168
  28. 028
    Blog postMedium · 2–3 daysadded 2026-10-08

    A deal agent that acts on the file: scenarios, borrower email drafts, document asks

    fa1937c (1,779 insertions, 29 files) lets the deal agent run scenarios, draft borrower emails and request documents, with every document audited and a per-deal inbox. The design question is what the agent may do versus only draft for a human to send.

    apps/crestborne-staging commit fa1937c
  29. 029
    Blog postMedium · 2–3 daysadded 2026-10-07

    Rewriting a demo as a platform in one day: Apollo's 20 learnings became rules

    geolab v1 was rewritten as Apollo in a day (about 40 commits). docs/DESIGN.md turned 20 lessons into numbered rules (L1–L20) before any code, and parallel fork agents built the spine against them. Walk through which rules held and which were dropped.

    apps/apollo docs/DESIGN.md; commits af5527e, 839286a, f95710c, 05bc0f3, 861a850; memory/project_apollo.md (104 tests green, migrate_v1 in 0.8 s)
  30. 030
    ThreadSmall · a dayadded 2026-10-07 posted to X · 2026-10-08

    ST_Distance_Sphere takes (lat, lon). v1 passed (lon, lat) everywhere.

    DuckDB's ST_Distance_Sphere wants ST_Point(lat, lon). Geolab v1 passed the reverse order, so distances were 30–50% off at 48–56°N. The bug was found only because the rewrite re-derived the analytics from scratch, and it became rule L21.

    apps/apollo commit 05bc0f3 (fix ST_Distance_Sphere axis order in analytics); memory/project_apollo.md rule L21
  31. 031
    Chart + threadSmall · a dayadded 2026-10-07 posted to X · 2026-10-09

    42 seconds to 3.6: precomputing bounding boxes for place stats

    Attached-place stats took 42 s. Precomputing place bounding boxes cut that to 3.6 s, and materiality over 830k pings × 3,557 places runs in 1.7 s. Chart the before and after, and show the one-line query change.

    apps/apollo commit 25f63b4 (precompute place bounding boxes); commit 073707a (cache per-place activity stats); memory/project_apollo.md measurements
  32. 032
    Blog postSmall · a dayadded 2026-10-07

    Review agents were interrupted mid-run, so the commit says 'unverified'

    Review agents were cut off partway through a 62-file change. Commit 896ed1c landed it labeled wip/unverified. Follow-up commits ce5320e and 1b4bf02 fixed the backend and frontend findings and checked them on the production build. Describe how to recover from half-finished agent edits without trusting them.

    apps/apollo commits 896ed1c, ce5320e, 1b4bf02
  33. 033
    Blog postMedium · 2–3 daysadded 2026-10-07

    Deleting explanations from a finance UI: 15 commits of 'numbers only'

    For the Crestborne partner review, the UI shed rule badges, source notes, policy explainers, SOFR source lines and internal reference numbers. Each deletion followed the same reasoning: the reader is a partner, not an analyst. Cover what stayed (per-field provenance on click) and what moved off the page.

    apps/crestborne-shadcn commits b552574, c83f15b, 424e828, 1701827, 94e3b3c, b80398a (crestborne-staging)
  34. 034
    ThreadSmall · a dayadded 2026-10-07 posted to X · 2026-10-10

    A parked feature flag and a reverted revert: title order in a deal journey

    Title order was committed by mistake, reverted in b439a87, restored in f3b0cd5, then parked behind CRESTBORNE_TITLE_ORDER (off) in 9432efb. The same day e7a5d1a made title wait for underwriting sign-off. Use it to show how a flag beats revert churn when the product rule isn't settled.

    apps/crestborne-shadcn commits e7a5d1a, b439a87, f3b0cd5, 9432efb
  35. 035
    Blog postMedium · 2–3 daysadded 2026-10-06

    Parallel pulls got my IP blocked: Colorado water data from CSV exports, not the REST API

    The DWR bulk REST API blocked the IP when pulls ran in parallel. The same 173k water rights and 593k well permits come cleanly from data.colorado.gov CSV exports. Covers the ingest design and the parcel join that follows.

    apps/waterrights commit 2f6fcc8 (24 files, 2,290 insertions); memory/project_waterrights.md
  36. 036
    ThreadSmall · a dayadded 2026-10-06 posted to X · 2026-10-07

    Crawling a county parcel site 200 parcels at a time

    The El Paso Spatialest crawl kept degrading until the browser context was recycled and not-found parcels were remembered. It ended with a full browser restart every 200 parcels. Three small commits in one day show what a long Playwright crawl needs to survive.

    apps/waterrights commits 0c03b1b, 871ffe7, 18c751b
  37. 037
    Blog postMedium · 2–3 daysadded 2026-10-06

    Chain of title from public records: one county gives grantor/grantee, the other charges for it

    El Paso exposes transfer history with grantor/grantee. Summit's assessor gives instruments only, with names behind the paid iCounty, and Weld's recorder terms forbid automated searches. This is a data-access map of what a public-records product can legally and practically include.

    apps/waterrights commits 48a6b25, 18c751b; memory/project_waterrights.md
  38. 038
    Blog postMedium · 2–3 daysadded 2026-10-06

    A property water report: search a parcel, get rights within 400 m, decrees and transfers

    The report joins parcels to nearby rights and wells, then adds decree links and transfers. A whole-property mode pulls in the owner's other parcels within 5 km and handles multi-part parcels. Explains why the radius and the owner grouping were chosen.

    apps/waterrights commits 7900af1, d31d791
  39. 039
    Blog postSmall · a dayadded 2026-10-06

    Going to market for a data product in one day: prospects, sample reports and an outreach test plan, all generated from the data

    The same day the water rights map shipped, the repo gained market research, prospect lists, sample reports and outreach drafts. A sample-builder loop bug had to be fixed. Shows how an agent-built dataset gets turned into a sales motion.

    apps/waterrights commits c9c2df1, 9c608c1
  40. 040
    ThreadSmall · a dayadded 2026-10-06 posted to X · 2026-10-08

    Refer, don't decline: three underwriting rules from a walkthrough with the client

    Feedback from a walkthrough changed the underwriting logic in one commit. Out-of-box deals are referred and not declined, LTV is computed on post-improvement value, and cure conditions are explicit. Each rule is a product decision that is easy to miss in code.

    apps/crestborne-staging commit 9a56fbd (55 files, 1,555 insertions)
  41. 041
    Blog postMedium · 2–3 daysadded 2026-10-05

    A 2:40 film from four local models and no API calls

    Wan 2.2 clips, ACE-Step music, Kokoro narration and faster-whisper captions, joined by ffmpeg into one finished piece on a single 3090 Ti. Cover the order of operations and which stage was the bottleneck (video at about 12 min per clip versus music at about 1 min per 3-minute track).

    ~/projects/videolab (gen.py, acestep/music.py, captions.py, assemble.py); memory/project_videolab.md
  42. 042
    VideoMedium · 2–3 daysadded 2026-10-05

    Watch the 2:40 space piece get built, stage by stage

    Show the finished final.mp4 with each layer added in turn: raw Wan clips, then music, then tape-warble narration, then word-timed captions. The audience sees what each local model contributes.

    ~/projects/videolab/final.mp4, assemble.py
  43. 043
    ThreadSmall · a dayadded 2026-10-05 posted to X · 2026-10-06

    Word-level timestamps to animated captions: whisper to ASS in one script

    Run faster-whisper on your own TTS narration to get word timings, then emit an ASS file with per-word animation. It is a small script, and the timestamps come from the generated audio, so there is no hand-sync.

    ~/projects/videolab/captions.py
  44. 044
    Blog postMedium · 2–3 daysadded 2026-10-03

    CPU offload ate 22GB of RAM; loading straight to the GPU fixed it

    diffusers' enable_model_cpu_offload() kept ~22 GB of Wan 2.2 weights in host RAM, pushed the box to 5% available with swap full, then OOMed in VAE decode. The fix: device_map="cuda", encode all prompts and free the text encoder before loading the transformer, tile the VAE, and run a watchdog that exits below 6 GB MemAvailable.

    ~/projects/videolab/gen.py; memory/project_videolab.md
  45. 045
    Chart + threadSmall · a dayadded 2026-10-03

    14.6 seconds per step: what a 5-second local video clip costs on one 3090 Ti

    Plot measured generation time: 2s/20-step smoke test ≈ 140 s versus 5s/1280×704/40-step ≈ 710 s (14.6 s/step). Show how frames and steps scale cost, and what that means for iterating on prompts locally.

    ~/projects/videolab/gen.py; memory/project_videolab.md
  46. 046
    ThreadSmall · a dayadded 2026-10-03

    Wan 2.2 5B ignores "drone glide" and "push-in"

    A local text-to-video model gave good people and landscape texture but didn't follow camera-move prompts and got physical cause-and-effect wrong. Share the prompt/output pairs and what that limits for a Claude-directed music video.

    ~/projects/videolab/prompts.json; memory/project_videolab.md
  47. 047
    Blog postMedium · 2–3 daysadded 2026-10-02

    What a public page of your own git history has to leave out

    26progress draws every 2026 project from git, but the interesting part is the exclusion list: employer repos, confidential, taxes, entity formation, partner checklists. Crestborne is reduced to 'Client operations platform' with no link. A curated catalog.py allowlist beats auto-discovery when the output is public.

    staticsites/26progress.build/catalog.py; commit ae3a383; memory/project_26progress.md
  48. 048
    Image + captionSmall · a dayadded 2026-10-02

    Every 2026 project, one row each, one mark per commit day

    Screenshot of the 26progress canvas chart: one row per project, one mark per commit day. Caption it with the shape of the year: which projects burst and which ran steadily.

    staticsites/26progress.softwaresoftware.dev/index.html and data.js; commit ae3a383
  49. 049
    ThreadSmall · a dayadded 2026-10-02 posted to X · 2026-10-03

    Hand-curated catalog, generated data: why new projects don't appear on their own

    build.py pulls only 2026 commits authored by Thatcher, while catalog.py is a hand-written list. Non-git projects need an explicit start=. It's deliberately not on a timer, because a public page should never publish something you haven't chosen.

    staticsites/26progress.build/build.py, catalog.py; commit ae3a383 (1080 insertions, 8 files)
  50. 050
    Blog postSmall · a dayadded 2026-09-30

    Swallowed exceptions hid a meeting-app bug for weeks

    meet's signaling server had `except: pass` on every handler and print() under systemd was block-buffered, so startup messages surfaced weeks late and the original drop cause is still unknown. The fix was logging first, then the reconnect logic.

    apps/meet commit 24e75c9 (server logging, PYTHONUNBUFFERED=1, MESH_DAEMON default 8910→8940)
  51. 051
    ThreadMedium · 2–3 daysadded 2026-09-30

    Ghost peers: why a WebRTC reconnect showed the other person twice

    After signaling sockets dropped, the client kept old peer connections, never re-offered, and dialed its own stale id. The fix: tear down all pcs, reconnect with ?prev=<oldid>, and have the server reap the ghost. Walk through the 5-tile repro.

    apps/meet commit 24e75c9, test_reconnect.py (reproduces bug, passes 10/10 locally and through Cloudflare)
  52. 052
    Blog postSmall · a dayadded 2026-09-30

    A stale what-if override masked the real number, so overrides now carry a fingerprint

    In the finance planner, a localStorage 2% Crestborne override silently masked the DB's 1% value after the seed changed. The fix fingerprints overrides against the DB docs and drops them when the docs change.

    personal/finance commit 3eb256f; memory project_finance_planning.md
  53. 053
    Blog postMedium · 2–3 daysadded 2026-09-29

    Personal finance planning with an AI: pure engine, git-ignored seed

    The finance planning layer splits into a pure `planning.py` engine with no personal data and a git-ignored `db/planning_seed.json` that holds every real number. Show the rule (edit the seed, reload, never patch the DB), why it lets the code stay committed, and how the agent is kept from writing income figures into tracked files.

    projects/personal/finance (commit 9ee4c0f, 9 files, +1415); memory/project_finance_planning.md
  54. 054
    Chart + threadSmall · a dayadded 2026-09-29 posted to X · 2026-09-30

    Reconciling AI-extracted income to the filed returns: 3 years exact, 1 off by Schedule C

    The earnings history was rebuilt from tax docs and checked against filed returns. 2020, 2021 and 2025 match exactly, and 2022 differs only by Schedule C expenses. Chart the by-source totals against the filed figures, and show which years have no return on disk and where the scenarios rest on estimates.

    projects/personal/finance commit 9ee4c0f; memory/project_finance_planning.md (gaps list)
  55. 055
    ThreadSmall · a dayadded 2026-09-29 posted to X · 2026-10-02

    Streaming a defense and kicker needs a schedule look-ahead, not this week's rank

    fflwatch gained D/ST and K streaming look-ahead for waiver research. Explain why a one-week ranking picks the wrong stream, what the look-ahead reads, and the playbook note added for DST claims.

    projects/tools/calwatch commit 42a2cc1 (8 files, +221/-17); projects/personal/fantasy-football commit 4060fe8
  56. 056
    Blog postSmall · a dayadded 2026-09-28

    Stop reading IP addresses as cell ids

    geolab's cell-tower lookup was treating IPv4 addresses in uploaded data as cell ids. Walk through how a dotted-quad passes a numeric-field sniff and what column-level validation replaced it. Includes the same commit's fix for a second instance leaking uploads and terminal state.

    apps/geolab commit 9854f4d
  57. 057
    Blog postMedium · 2–3 daysadded 2026-09-28

    Asking Apple where a Wi-Fi network is, without an account

    geolab added Apple as a second network lookup service, then `geo apple around` and a map layer. Cover what the lookup returns, why sampled access points just outside an empty circle are worth a follow-up query, and the limits of the data.

    apps/geolab commits ebe3a25, a447cb7, c9d0d17, e8f9c89
  58. 058
    Blog postMedium · 2–3 daysadded 2026-09-28

    A Windows VM any developer can make in one command

    Team KB claims first-class Windows support, but nobody had a Windows machine to test on. tools/windows-vm builds one from scratch (408 lines). Explain the design choices and what it caught that Linux CI could not.

    products/team-kb commit 78badc2
  59. 059
    ThreadSmall · a dayadded 2026-09-28 posted to X · 2026-09-29

    CI said green while macOS was failing

    Team KB's macOS job was allowed to fail, so a real bug hid behind a passing run. That bug corrupted the Obsidian vault list on macOS. Show the two-line CI change and the 27-line fix, and note that tests no longer need Obsidian installed.

    products/team-kb commits 24b9289, 738e661, 17ab4ff
  60. 060
    Blog postMedium · 2–3 daysadded 2026-09-28

    Publish to customer marketplaces as a service identity only

    marketplace-factory used to push with admin credentials embedded in scripts. Cover the move to a dedicated service identity: what got removed, what the 155-line change touched across 7 files, and why least privilege matters when the publisher is an agent.

    aicotx/marketplace-factory commit 8ed5617
  61. 061
    Blog postSmall · a dayadded 2026-09-22

    The copy-lint score that turned 'this sucks' into a number

    Thatcher's actual complaint about aicotx.com was vague ('the copy and animations really suck'); building copy-lint.py to score em-dash antithesis and word-repetition turned that into a fixable, re-runnable gate. Walk through what it measures and why description-driven generation reverts to model house style no matter how the prompt is worded.

    memory/feedback_frontend_craft_gates.md; ~/.claude/skills/frontend-craft/scripts/copy-lint.py
  62. 062
    Chart + threadSmall · a dayadded 2026-09-22 posted to X · 2026-09-27

    7.14 vs 0.35: aicotx's copy score against six real companies

    Bar chart of copy-lint scores for aicotx.com v3 home page (7.14) against Basecamp, Stripe, ThoughtWorks, Clearleft, Igalia, and Pentagram (0.35-1.33) — the gap that made 'the copy sucks' measurable instead of a vibe.

    memory/feedback_frontend_craft_gates.md (2026-09-22 measurement)
  63. 063
    Short (60s)Small · a dayadded 2026-09-22

    One fade-up, seven sections, and the hero that never moved

    motion-check.mjs caught the actual bug on aicotx v3: every section got the same 0.7s fade-up-on-scroll except the one thing that should have moved — the hero heatmap, the site's signature visual. Show the sheet.png diff and the fix (one signature motion on the hero, hover-only elsewhere).

    memory/feedback_frontend_craft_gates.md; ~/.claude/skills/frontend-craft/scripts/motion-check.mjs
  64. 064
    Chart + threadSmall · a dayadded 2026-09-21 posted to X · 2026-09-27

    A cure reserve, priced against three candidate policies

    When a deal misses the DSCR floor, staging doesn't just reject it — it computes a cure reserve and runs it against several candidate policies on that specific deal's numbers, so you see what each policy actually costs before picking one.

    apps/crestborne-staging, commit d800f90 (cure reserve on a dscr miss, candidate policies side by side, per-deal arithmetic sheet)
  65. 065
    Blog postMedium · 2–3 daysadded 2026-09-21

    The diligence tab reads the document instead of asking you to retype it

    New diligence tab pulls fields straight out of uploaded documents and pipes in a live SOFR feed, replacing manual entry with extraction — the underwriting workflow shrinks by a step, not a UI polish.

    apps/crestborne-staging, commit d90a972 (diligence tab, document extraction, live SOFR)
  66. 066
    Short (60s)Small · a dayadded 2026-09-21

    Your co-founder's checklist, read-only

    Built a two-login shared task list for splitting NOV LLC cleanup with a partner: each person can only check off their own items but sees the other's list live, grayed out — no status pings, just a shared source of truth.

    apps/partners, commit d225b3e (NOV LLC partner checklist app, 1328 insertions) + partners.softwaresoftware.dev
  67. 067
    Short (60s)Small · a dayadded 2026-09-21

    Scoring which SOS hit is actually the employer

    A name search against Secretary of State records returns a pile of plausible-looking matches; the tool scores each one for how likely it is the real current employer instead of dumping a raw hit list.

    tools/garnishee-check, commit 437d3fa (score SOS hits as plausible employers)
  68. 068
    Blog postSmall · a dayadded 2026-09-21

    The recording waits for the voiceover, not the other way around

    The demo-video pipeline renders narration first, then a cap() helper blocks each Playwright scene until the spoken line would have finished — so the recording paces itself to the audio instead of audio getting stretched or cut to fit clips.

    ~/.claude/projects/-home-thatcher/memory/reference_local_tts_and_demo_video.md, used in ~/Documents/crestborne/demo/2026-09-21-whats-new/
  69. 069
    Blog postSmall · a dayadded 2026-09-18

    Six places I call a text model to make a yes/no decision

    Audit of my own pipelines for LLM calls whose output is really a typed choice, not prose: mailwatch's tier classifier (a sonnet `claude -p` every 5 minutes), conduit's haiku router, dispatcher unmatched-event routing, the slackwatch/ghwatch keyword gates, geolab column-role labels, and sentinel's send gate. It scores each against a typed-decision model (Jev: Choice/Score/yes-no probability, 70-500ms, $0.042/Mtok input, output free) and its documented weak spots (literal instruction reading, no counting or date comparison, injectable state). It also covers what leaves the box when the classifier is a cloud API. This is an assessment, not a benchmark, so the post should say so.

    ~/.claude/projects/-home-thatcher/memory/reference_jev_typesafe.md (researched 2026-09-18, nothing built yet)
  70. 070
    Blog postMedium · 2–3 daysadded 2026-09-15

    The chess tutor builds its own drills while you're still talking to it

    chess-trainer's new Ask chat wires the coaching agent to a ct toolbox that can generate widgets and drills as chat artifacts mid-conversation, instead of requiring a separate offline build pass like the earlier fable drill program.

    apps/chess-trainer commit 6bba007 ("ask: tutor agent chat with ct toolbox, widgets, chat drills", 21 files, 1542 insertions)
  71. 071
    ThreadSmall · a dayadded 2026-09-15 posted to X · 2026-09-25

    chess-trainer went phone-first in one commit

    A desktop-built trainer got a bottom tab bar, swipeable board, and an installable PWA manifest in a single day's commit — what changes when the primary surface flips from mouse-and-keyboard to a phone screen.

    apps/chess-trainer commit d1edb0f ("mobile: bottom tab bar, phone chat layout, board swipe, installable manifest", 19 files, 265 insertions)
  72. 072
    Image + captionSmall · a dayadded 2026-09-15

    A name isn't a location: geolab's LOI rule, enforced in code

    geolab reports used to cite locations of interest by name alone; now every citation runs through a loi_ref(name) helper that appends lat/lon to five decimals, turning a prose convention into something the code enforces after a report came back with ambiguous names.

    apps/geolab commit 60d0914 ("require coordinates after every cited LOI name") + memory/feedback_loi_names_with_coordinates.md
  73. 073
    Short (60s)Small · a dayadded 2026-09-14

    The filter that only ever covered the tailnet, not the house

    Assumed the whole house was running through Pi-hole's NSFW/social blocklists since July. A 2026-09-14 check showed zero WiFi clients hit Pi-hole in 24 hours — the router was handing WiFi devices 1.1.1.1/8.8.8.8 directly, so only Tailscale-connected devices were ever actually filtered. Two months of a safety net that only covered half the house.

    ~/pihole/docker-compose.yml, reference_pihole_dns.md memory note updated 2026-09-14
  74. 074
    Blog postSmall · a dayadded 2026-09-11

    One playbook, two readers: counsel and the AI both negotiate off the same file

    sign.aicotx.com's new counsel feature (Revise/Review/Ask on any contract PR) draws its negotiating stance from the same playbook doc human counsel uses — change a position once and both the AI agent and the lawyers are working off the updated line, instead of a doc for people and a prompt for the model.

    ~/projects/aicotx/contracts commit 8060376 (playbook: our negotiating positions for counsel and humans) + ~/projects/aicotx/sign commit 1411a0b (counsel: AI contracts assistant via taskpilot)
  75. 075
    Short (60s)Small · a dayadded 2026-09-11

    Counsel's agents don't inherit the repo's cwd

    The contracts AI assistant runs as a taskpilot agent, and taskpilot starts each task in its own task directory, not sign's working directory — so counsel had to switch to absolute paths everywhere or its edits landed in the wrong place.

    ~/projects/aicotx/sign commit b914f82 (counsel: start agents in taskpilot's task dir, work by absolute path)
  76. 076
    Blog postMedium · 2–3 daysadded 2026-09-10

    A contract negotiation is a pull request

    sign.aicotx.com maps the legal lifecycle onto git: new contract from a template is a branch, redlines happen as PR review comments, merge is agreement, then a pinned commit gets SHA-256'd and emailed for signature with an audit.json committed back into the repo. Walk through why that beats a shared-drive Word doc for a small team that already lives in git.

    ~/projects/aicotx/sign commit 9bfbb00 (aicotx/sign); memory/project_sign_aicotx.md
  77. 077
    Short (60s)Small · a dayadded 2026-09-10

    Markdown turned (c) into (c)opyright, and it almost shipped in a contract

    markdown-it's 'replacements' typographic rule silently rewrites (c) to © in rendered contract text — a drafting note like MSA section 15's '(c) concede it deal-by-deal' comes out wrong. One-line fix: turn the rule off. Small, concrete bug with a screenshot of before/after render.

    ~/projects/aicotx/sign (aicotx/sign), gotcha noted in memory/project_sign_aicotx.md
  78. 078
    ThreadSmall · a dayadded 2026-09-10 posted to X · 2026-09-24

    Org policy turned off deploy keys, so a contract app got its own GitHub App

    aicotx's org disabled repo deploy keys, which broke the planned auth path for sign.aicotx.com. The fix was a GitHub App scoped to just two repos (contracts + legal-documents) via the manifest flow — and the manifest's user-email permission key turned out to be 'emails', not the documented-sounding 'email_addresses'.

    ~/projects/aicotx/sign commit a18065b, a456a1f; memory/project_sign_aicotx.md
  79. 079
    Blog postMedium · 2–3 daysadded 2026-09-10

    One folder becomes ten repos in an afternoon

    aicotx's whole workspace — KB, legal, contracts, digital assets, marketing site, lab, Clearance, sign — was one working tree until 2026-09-10, when it split into one private GitHub repo per concern so two co-founders could hold org-owner access without every repo sharing history. The rule that came out of it: no host config (nginx, systemd, deploy scripts) ever goes in any of the ten.

    hq-plugins commits 69dd7e7/b01b214; projects/aicotx/{contracts,digital-assets,knowledge-base,legal-documents,marketing-site,lab,products/clearance,sign} initial commits, all 2026-09-10; memory/reference_aicotx_github_layout.md
  80. 080
    Blog postSmall · a dayadded 2026-09-09

    A 30-hex board needs backtracking, not a shuffle

    Catan's 5-6 player expansion adds hard constraints (resource adjacency, number-token spacing) that a random shuffle can violate; catanizer's new solver backtracks until it finds a legal 30-hex layout. Walk through why naive randomization fails and what the constraint set actually is.

    apps/catanizer, commit 8120b93 (2026-09-09, 79 insertions/29 deletions, 2 files)
  81. 081
    ThreadSmall · a dayadded 2026-09-09 posted to X · 2026-09-24

    The heat map's first hotspot was null island

    geolab shipped a heat-map overlay, and the first thing it lit up was a fake cluster at placeholder coordinates — which is what pushed the very next commit: a filter that detects and excludes placeholder GPS points from presence analytics. Tell it as cause-and-effect across two commits in one day.

    apps/geolab, commits c1434ec (heat-map overlay) and 7e478cd (placeholder-coordinate detection, 300 insertions/6 files), 2026-09-09
  82. 082
    Blog postMedium · 2–3 daysadded 2026-09-09

    Three Dominion datasets, three text formats, one merge script

    The Dominion Strategy wiki sits behind an Anubis proof-of-work wall, so dominion-or-no's card data came from three GitHub mirrors instead — each with a different text convention (stripped VP symbols needing regex restoration, <VP>/Coin tokens, Rising Sun costs from a third source). Five of the 158 AI-authored fakes collided with real card names and had to be renamed.

    staticsites/dominion-or-no.softwaresoftware.dev, commit e81b106 + fakes.py/build_data.py (d2f2736); memory/project_dominion_or_no.md
  83. 083
    Blog postMedium · 2–3 daysadded 2026-09-08

    One board, three sources: chess-trainer's opening explorer merges your games, lichess, and masters

    The openings explorer plots your own game history, the lichess database at your rating band, and the masters database on the same board per move, then asks a coach agent for a lesson on the line you're looking at. Explain why merging sources beats picking one — you see where your repertoire diverges from what actually gets played against you versus what titled players do.

    apps/chess-trainer commit 71ab09a (20 files, 4678 insertions) — openings/*, coach lesson endpoint, spaced-repetition repertoire drills
  84. 084
    Short (60s)Small · a dayadded 2026-09-08

    Coach-generated opening lines get clipped at the first illegal move

    The model-line feature for chess-trainer's opening lessons doesn't trust the coach's output verbatim — it replays each suggested line against the engine and truncates it the moment a move is illegal, rather than showing a hallucinated continuation. Small, concrete guard against LLM chess hallucination.

    apps/chess-trainer commit 9ef3a8f — 'keep coach lines up to their first illegal move, neutral due badge, assets v8'
  85. 085
    ThreadMedium · 2–3 daysadded 2026-09-08

    geolab turns raw pings into named places you never labeled

    The new investigations workspace clusters a device's raw location pings into discovered locations without any seeded fence — home, work, and recurring stops emerge from the data itself. Walk through what counts as a 'discovered' location versus a manually drawn fence.

    apps/geolab commit 4e579a4 (15 files, 4270 insertions) — investigations workspace, discovered locations
  86. 086
    Short (60s)Small · a dayadded 2026-09-08

    A Shodan layer with no Shodan API key

    geolab's exposure layer pulls Shodan host data through the browser bridge — driving a logged-in browser tab instead of paying for API access. Show the tradeoff: no key, no rate-limit tier, but also no server-side automation ban risk if you keep it to interactive lookups.

    apps/geolab commit 4e579a4 — shodan exposure layer, per project_geolab.md memory notes
  87. 087
    ThreadMedium · 2–3 daysadded 2026-09-08

    9 builds, 3 models, one brief: judging AI-built SaaS blind

    Same SaaS spec given to sonnet, opus, and fable across three case studies (CRE, investing-mock, regwatch) — 9 headless builds deployed to their own subdomains, then judged blind so the model that wrote the judging code doesn't know which build is its own. Lay out the design before the results land: why blind judging, why three unrelated case studies instead of one.

    ~/projects/aicotx/lab/exp-saas-build-matrix, memory project_saas_build_matrix.md — runner.py/deploy.sh/judge.py pipeline, started 2026-09-08
  88. 088
    ThreadSmall · a dayadded 2026-09-07 posted to X · 2026-09-23

    Google Flights has no price API, so flightwatch reads the cheapest fare and guesses the rest

    flightwatch polls a plain GET to Google Flights search HTML (tfs/tfu blobs, no JS) every 3 hours, pulls the lowest nonstop (Basic) fare, and estimates Economy as basic+$120 rather than trying to parse fare-class rows out of the page. Show the config thresholds (text at ≤$680, on further ≥$25 drops, once on a ≥$150 climb) and why a fixed markup beat scraping a fragile DOM.

    ~/.config/flightwatch/config.json, $SENTINEL_ROOT/flightwatch/, systemd unit flightwatch.service; memory/project_costa_rica_trip.md (built 2026-09-07)
  89. 089
    Short (60s)Small · a dayadded 2026-09-07

    Pi-hole can't block Shorts because Shorts and regular videos share a host

    Thatcher asked to unblock YouTube on the phone but keep Shorts blocked — impossible at DNS since /shorts/ and /watch resolve to the same domain. The fix moved from network-layer (Pi-hole wildcard) to page-layer (a userscript that hides cards under a duration threshold and rewrites /shorts/ID to /watch?v=ID). One clip showing the redirect firing on click.

    ~/projects/softwaresoftware/projects/personal/youtube-length-filter/youtube-length-filter.user.js; memory/reference_pihole_dns.md (youtube unblocked 2026-09-07), memory/project_youtube_length_filter.md
  90. 090
    Image + captionSmall · a dayadded 2026-09-07

    The duration badge said 29:40 twice, and the anchored regex missed every video

    YouTube renders the length badge text doubled in the DOM ('29:40\n29:40'); a regex anchored to match-from-start read it as garbage and hid nothing. Screenshot the raw badge text next to the before/after regex, one line each.

    ~/projects/softwaresoftware/projects/personal/youtube-length-filter/youtube-length-filter.user.js (badge parsing fix, tested via browser bridge 11/22 hidden at 700s threshold)
  91. 091
    Blog postSmall · a dayadded 2026-09-06

    RSS undercounts a leak: the second bug in session-bridge's orphan channels

    channel.mjs orphans hit 1.3-1.65GB each and drove memguard from WARN to CRIT, but the first sweep script missed the worst offender because RSS excludes swapped-out pages — screening by ppid==systemd and adding VmSwap from /proc/<pid>/status was the actual fix, not a bigger RSS threshold.

    ~/.claude/projects/-home-thatcher/memory/reference_session_bridge_channel_leak.md — orphans under tab(1144318).scope held 9.0GB after ~50 hours, SIGTERM freed RAM 4.7GB→11GB
  92. 092
    Blog postSmall · a dayadded 2026-09-06

    Accurate but not actionable: chess-trainer gets a second model

    Sonnet's coaching diagnosis was correct but Thatcher couldn't do anything with it, so a second taskpilot agent on model fable was added whose only job is turning diagnosis into drills he can play against Stockfish — a concrete split between explaining a weakness and generating something to practice.

    apps/chess-trainer commit 45c2b7e (2026-09-06) — chess-builder agent, model fable, per memory/project_chess_trainer.md 'sonnet's diagnosis was accurate but not actionable'
  93. 093
    Chart + threadSmall · a dayadded 2026-09-06 posted to X · 2026-09-23

    Four drill types, one source: your own lost games

    chess-trainer's drill generator sorts a player's games into four buckets — convert (win won middlegames vs a 2000 bot), endgame, tactics/missed mates, and openings drilled against the replies real opponents played — all mined from the same game history instead of generic puzzle sets.

    apps/chess-trainer commit 45c2b7e, pages #/train and #/d/<id>, per memory/project_chess_trainer.md
  94. 094
    Blog postSmall · a dayadded 2026-09-05

    "I don't want to hit the actual API": chess-trainer's coach becomes a taskpilot agent

    Chess coaching needed real reasoning over lichess game data, but a per-request claude -p call didn't fit how Thatcher wants AI work to run. Walk through the swap to a persistent taskpilot agent messaged via session-bridge, with claude -p demoted to an opt-in fallback in Settings.

    apps/chess-trainer commit 5380499; memory/feedback_no_headless_claude_p_in_apps.md
  95. 095
    Blog postMedium · 2–3 daysadded 2026-09-05

    A folder of location exports, a dry run, then a PDF

    geolab's new agent layer ingests messy, mixed-format location exports, previews the parse before touching the database, and turns profile/network/hotspot findings into a PDF via headless Chrome. Show the dry-run step and why it exists before any write.

    apps/geolab commit 70c565a
  96. 096
    Chart + threadSmall · a dayadded 2026-09-05 posted to X · 2026-09-22

    1M visits in 2 seconds: pushing the crowd query into SQL

    geolab's crowd-occupancy card moved from app-level looping to a DuckDB temp-table plus ASOF join, and the DB call moved off the event loop. Show the query shape and the timing before/after on real multi-year ping data.

    apps/geolab commit b9fba35
  97. 097
    Short (60s)Small · a dayadded 2026-09-05

    When does a visit end: leaving the box, or going quiet

    geolab's visit detector needed a second exit condition beyond a geofence crossing: a max_gap_min silence timeout, because a track can go dark without ever leaving the bbox.

    apps/geolab commit 27bf6c0
  98. 098
    Short (60s)Small · a dayadded 2026-09-05

    The 35B model ran ingest, profile, and report unassisted

    geolab's local Qwen3.6-35B (not Claude) executed the new agent playbooks end to end without hand-holding the same day they were written. A short eval note on what a mid-size local model already handles unsupervised.

    apps/geolab commit 70c565a; memory/project_geolab.md (2026-09-05 agent layer note)
  99. 099
    Short (60s)Small · a dayadded 2026-09-04

    The pty child that made tmux hold the socket

    geolab's opencode pane is a pty over a websocket, spawned into a tmux session; without closing inherited fds in the child, tmux inherited the listening socket itself and refused to die cleanly. One line, os.closerange(3,...), fixed it.

    apps/geolab commit ae2b64d (2026-09-04), 'close inherited fds in pty child so tmux doesn't hold the listening socket'
  100. 100
    Blog postSmall · a dayadded 2026-09-04

    A time window that never lies about when you left

    geolab's visit query selects any visit overlapping the window, then reports the real enter/exit timestamps even if they fall outside it — clipping them would silently misreport how long someone actually stayed.

    apps/geolab commit 5267e4d (2026-09-04), 'visits window selects overlapping visits, never clips enter/exit times'
  101. 101
    ThreadSmall · a dayadded 2026-09-04 posted to X · 2026-09-22

    geolab: fences, pings, visits, crowds, and a terminal that draws on the map, in one day

    Ten commits on 2026-09-04 go from a bare Leaflet+DuckDB scaffold to hand-drawn geofences, time-series visit detection, per-device and per-crowd cards, and an embedded opencode pane that edits the map live over SSE.

    apps/geolab, commits f04e6b3 through 6619f40, all dated 2026-09-04
  102. 102
    Blog postSmall · a dayadded 2026-09-04

    116GB of models that never fit in 24GB of VRAM

    Three Qwen3-Coder-Next 80B quants sat on llm.softwaresoftware.dev for weeks before the numbers caught up: llama.cpp's --fit projected 50GB of device memory for the Q4, the box had 24GB, and the load itself took 2.5 minutes while swap was already full. Deleted them everywhere at once.

    memory/project_llm_endpoint.md, 2026-09-04 update ('all three Qwen3-Coder-Next 80B quants... were DELETED')
  103. 103
    Short (60s)Small · a dayadded 2026-09-04

    The installer that would start two daemons into one session

    Moving idle-compact onto the shared daemon capability meant its systemd unit disappeared, but daemon-manager's installer unconditionally runs systemctl start — so an already-running instance plus a fresh install would both type /compact into the same idle session.

    plugins/apps/idle-compact commit 0db827f (2026-09-03), 'run as a managed daemon via the daemon capability'
  104. 104
    Blog postMedium · 2–3 daysadded 2026-09-03

    How many shards fit in memory: conduit's eviction policy

    Conduit went from 'keep every worker session alive forever' to a bounded pool with provisional admission, idle-ranked eviction, and pinning in one commit — walk through why unbounded warm sessions don't scale and what the pool status view actually measures (per-turn cache usage, warmth).

    tools/conduit, commits c7821c7 (bound the pool) and d57cc66 (measure the pool)
  105. 105
    ThreadSmall · a dayadded 2026-09-03 posted to X · 2026-09-21

    Shards become subagents: exposing long-lived sessions over MCP

    Conduit's worker sessions were router-only until commit 70e5670 turned them into callable subagents over MCP — with locking so two callers can't drive the same shard at once, and a recursion guard because a shard can now call itself through the same MCP surface.

    tools/conduit, commit 70e5670 (expose shards as subagents over MCP, with locking and a recursion guard)
  106. 106
    Short (60s)Small · a dayadded 2026-09-03

    Wrong by lunchtime: conduit's same-day cwd correction

    Conduit shipped a claim about how shard cwd binding worked, then corrected it in the next commit the same day after adopting desktop-app chats as shards exposed the assumption as false — a small honest story about how fast a wrong architectural claim gets caught when you're dogfooding your own tool hourly.

    tools/conduit, commits 9d4f4fb (adopt claude code desktop chats as shards) and fd8f7cd (record shard cwd at adoption; correct the cwd-binding claim)
  107. 107
    Blog postMedium · 2–3 daysadded 2026-09-03

    One dbus method is gated, the sibling isn't: building idle-compact's yakuake driver

    Building idle-compact meant driving yakuake sessions with zero visible UI feedback: sendText is blocked by EnableSecuritySensitiveDBusAPI even with the flag set, but runCommandInTerminal isn't gated at all — and Enter has to be its own dbus write or the TUI reads it as a paste and swallows the whole line.

    plugins/apps/idle-compact, commit 11d2f17 (initial build) plus memory/project_idle_compact.md notes on the yakuake/konsole dbus asymmetry
  108. 108
    Chart + threadSmall · a dayadded 2026-09-03 posted to X · 2026-09-21

    taskpilot's first non-Claude-Code provider

    taskpilot-opencode forks the long-running-autonomous-session harness onto opencode instead of Claude Code — the first time the harness runs on a swappable backend, which is also the first real workload that could route to the self-hosted llm.softwaresoftware.dev models instead of the API.

    plugins/providers/taskpilot-opencode, commit ea77042 (fork the harness onto opencode)
  109. 109
    ThreadSmall · a dayadded 2026-09-01 posted to X · 2026-09-20

    [CONFIRM] markers instead of guesses

    The AI-drafted operating agreement didn't fill in the ambiguous parts — it flagged them as [CONFIRM] and left them for a human decision. Closing every open bracket without a lawyer is what actually made the LLC's founding documents final.

    ~/projects/aicotx/legal, commit cc2b560 'resolve every open [CONFIRM] without counsel — Thatcher's call', plus 0da248e 'apply the review: OA amendments + every open item resolved'
  110. 110
    Short (60s)Small · a dayadded 2026-09-01

    The compliance step that turned out to be a no-op

    Ran the BOI/FinCEN question for a new domestic LLC and the answer was: not required, exemption applies. A five-minute check that would otherwise cost a filing (or a lawyer's hour) to confirm.

    ~/projects/aicotx/legal, commit 31a970c 'compliance: BOI not required (domestic exemption), deadline register, name propagation'
  111. 111
    Blog postSmall · a dayadded 2026-08-31

    DSCR floor as a hard gate, not a score input

    Commit f8c37c5 moved the DSCR floor out of the weighted screening score into a hard gate-1 pass/fail alongside the 5y term on 25y amortization structure. Walk through why a debt-service-coverage floor is the one number in CRE underwriting you don't average away — a deal either clears it or it doesn't, and blending it into a score just hides a disqualifying loan behind a decent composite.

    apps/crestborne-staging f8c37c5 (12 files, +116/-34)
  112. 112
    Chart + threadSmall · a dayadded 2026-08-31 posted to X · 2026-09-19

    Pro-forma NOI vs. present-day NOI, same property

    Commit cbf0039 switched the underwriting basis from a forward-looking value/NOI projection to present-day actuals. Show the same deal underwritten both ways side by side — the gap between what a pro-forma promises and what the property is doing today is exactly the gap a lender is supposed to price for.

    apps/crestborne-staging cbf0039 (5 files, +29/-20)
  113. 113
    Chart + threadSmall · a dayadded 2026-08-31 posted to X · 2026-09-20

    128K context cost 23 tokens/sec

    Bumping every Qwen3.6-35B config on the self-hosted endpoint from 32K to 128K context (native ceiling per the GGUF metadata, not an arbitrary cap) required q8_0 KV cache quantization to fit — generation dropped from 152 tok/s to 129 tok/s for 4x the usable context. That's the actual exchange rate for context length on a single-GPU box, not a vendor's marketing number.

    memory/project_llm_endpoint.md (config.yaml, 2026-08-31 edit) — llama-swap ~/.config/llama-swap/config.yaml
  114. 114
    Short (60s)Small · a dayadded 2026-08-31

    $40k funded, zero invested

    The investing pipeline's researcher/critic agents have a live proposal queue and a real trust gate, but as of the PNC holdings intake on 2026-08-31 the $40k that got wired in still sits in cash — the bottleneck isn't the automation, it's that nothing has cleared the critic yet. Worth a short on what an AI pipeline looks like the day after it goes live and before it's proven itself.

    memory/project_investing.md, PNC Investments x7850 holdings intake 2026-08-31
  115. 115
    Blog postSmall · a dayadded 2026-08-30

    No vesting, no 83(b): the inactivity call right instead

    We put vesting back into the AICOTX operating agreement, then ripped it out the same day once the 83(b) 30-day filing deadline and look-through mechanics onto GRAV's tranches got real. The replacement is simpler: units fully vested at issuance, and on cessation of service the company/members can buy the departing person's stake at fair value. Explain why a buyout right beats vesting for a three-person services LLC.

    ~/projects/aicotx (hq-plugins KB commits 8fe649a, bd7ebe0, 2a33d1a, 2026-08-30) + memory/project_ai_consulting.md
  116. 116
    Blog postMedium · 2–3 daysadded 2026-08-30

    /flow-check: a pre-commit gate that spins up its own instance

    Crestborne's new pre-commit gate boots an ephemeral instance of the app and runs a verification agent per user flow before the commit lands — not a linter, an actual click-through. Walk through why static checks weren't catching UX regressions and what the ephemeral-instance-plus-agent pattern looks like in practice (17 files, 584 lines).

    ~/projects/softwaresoftware/projects/apps/crestborne commit d2fb65a (2026-08-30)
  117. 117
    Blog postSmall · a dayadded 2026-08-30

    One commit, 4,272 deletions: cutting a loan app down to two stages

    Crestborne's lifecycle got reduced to intake → indicative in a single commit that removed more code than any feature ever added. Cover the reasoning: which stages got cut, why doing less well beat doing more badly for the demo, and what 'reimagine the lifecycle' meant in practice.

    ~/projects/softwaresoftware/projects/apps/crestborne commit ec4d9c3 (2026-08-30, 67 files changed, 681(+) 4272(-))
  118. 118
    Short (60s)Small · a dayadded 2026-08-30

    Red screens never mint a letter

    A live-sweep bug fix in Crestborne's assurance flow: if the evidence check comes back red, the pipeline must not proceed to generate the approval letter regardless of what else looks fine. A small, concrete fail-closed pattern for any pipeline that ends in an artifact someone signs.

    ~/projects/softwaresoftware/projects/apps/crestborne commit b0ac382 (2026-08-30, 'red screens never mint a letter; restore evidence overlays')
  119. 119
    Blog postSmall · a dayadded 2026-08-30

    geodrop: a realtime map for a dataset you haven't published anywhere

    Built in one commit (2,013 lines, zero prior history): a local realtime map tool that doesn't need your data hosted or piped through a cloud API first. Compare against realtime-fleet's public/live-feed model — same map stack, opposite assumption about where the data lives.

    ~/projects/softwaresoftware/projects/data-analysis/geodrop commit 5146370 (2026-08-30)
  120. 120
    Blog postMedium · 2–3 daysadded 2026-08-30

    Agents propose, I execute: a trust gate for an AI investing pipeline

    The new investing layer lets invest-researcher and invest-critic agents write to a proposals table and nowhere else — Thatcher approves by SMS and places every trade by hand. Use the MU proposal (filed post-earnings, then weakened by the critic agent from a clean entry to a conditional one) as the worked example of researcher-critic disagreement changing the outcome.

    ~/projects/softwaresoftware/projects/personal/finance commits b2df494, 346ba40, eb4d4f0 (2026-08-30) + memory/project_investing.md
  121. 121
    Short (60s)Small · a dayadded 2026-08-29

    Dove is a bird and a brand: the collision-guard set

    A search-filter matcher for brand names hits a wall when the brand is also a common English word — Dove, Mars, Galaxy, Ring, Swift, Dolphin. The fix is a GENERIC_WORDS exception set that restricts those specific brands to exact product-row matches only, plus accent folding (Nescafé -> Nescafe) so matching doesn't silently miss.

    ~/projects/humane/src/content/filter.js, commit ccfaa75
  122. 122
    Blog postSmall · a dayadded 2026-08-29

    Flag instead of hide: humane's same-day reversal

    First commit hid flagged Amazon/Walmart search results outright. Second commit, same day, reverses it: dim the listing, tag it, and put the sourced evidence in a click-through popover instead of erasing it. The reasoning: hiding results looks like censorship and removes the user's ability to check the claim; showing evidence doesn't.

    ~/projects/humane commits 94f8db3 -> 65bc8a2
  123. 123
    Chart + threadSmall · a dayadded 2026-08-29 posted to X · 2026-09-19

    62 companies, 4 sector agents, one merge script

    Four parallel research agents each produced an independent JSON corpus of labor-abuse evidence; a merge script dedupes by slug AND by overlapping domain, keeps the more-severe rating on conflict, and swaps dead source links for Wayback snapshots before anything ships. Chart the 12 red / 40 yellow / 10 green rating split across sectors.

    ~/projects/humane/scripts/merge_corpus.py + corpus/corpus.json, commit ccfaa75 (7316 insertions)
  124. 124
    Blog postMedium · 2–3 daysadded 2026-08-29

    The chat server that can't read its own messages

    backchannel's threat model isn't just the network, it's the operator: ciphertext is all the server ever stores, and there's no public HTTPS path at all — it 404s — so the app only exists inside the tailnet. That's a different design point than 'we use TLS.'

    ~/projects/softwaresoftware/projects/apps/backchannel, commit 793262b (initial commit, 1764 insertions)
  125. 125
    Blog postMedium · 2–3 daysadded 2026-08-29

    Your friend's laptop, your chat UI

    agent-hub lets someone else drive their own Claude Code session through your web chat without opening a port on their machine: the connector dials out over a websocket, so NAT isn't a problem, and each minted key maps to exactly one agent, one owner.

    ~/agent-hub/hub.py, ~/agent-hub/public/connector.py, ~/agent-hub/mint.py
  126. 126
    Blog postSmall · a dayadded 2026-08-28

    Deleting the explain button

    Crestborne's deal page shipped with an AI explain panel, a deal score, and a journey clock. All three came out in one commit and got replaced with an embedded live chat — because a running conversation answers the question better than a static summary ever did.

    apps/crestborne-staging, commit b015f15 (simplify deal page: drop explain/score/journey-clock, embed live deal chat)
  127. 127
    Chart + threadSmall · a dayadded 2026-08-28 posted to X · 2026-09-17

    Rank cliff vs. marginal-starter threshold

    A fantasy roster tool used to flag 'startable' players by where they fell in positional rank — a cliff. Switching to a marginal-starter projection threshold changes who gets flagged, especially at the shallow end of a 10-team league. Plot the same roster under both definitions side by side.

    personal/fantasy-football, commit 7c7dad9 (startable = marginal-starter projection threshold, not rank cliff)
  128. 128
    Short (60s)Small · a dayadded 2026-08-28

    The league site that can't see your playbook

    austifornia.softwaresoftware.dev generates the same startable/waiver insights for every team in the league from public rosters and free-agent data — on purpose it never touches the private strategy notes sitting one directory over, so the site can't be accused of favoring its builder.

    personal/fantasy-football/site (austifornia.softwaresoftware.dev), commit 2547f85; kb/strategy.md deliberately excluded per memory/project_austifornia_site.md
  129. 129
    Blog postSmall · a dayadded 2026-08-28

    46GB free, swap 100% full

    Cold-loading an 80B model mmaps 36GB and floods page cache, which pushed the desktop's anonymous memory into swap even with tens of gigabytes sitting idle. The fix wasn't more swap, it was telling the kernel to evict cache instead of apps: vm.swappiness=10.

    ~/.claude/projects/-home-thatcher/memory/project_memguard.md (2026-08-28 entry: swap grown 2G→16G, swapoff/swapon drain, /etc/sysctl.d/90-swappiness.conf)
  130. 130
    Chart + threadSmall · a dayadded 2026-08-28 posted to X · 2026-09-18

    One flag: 90 tok/s to 282

    Prefill throughput on a CPU-offloaded MoE model tripled by raising llama.cpp's ubatch size from the 512 default to 2048 — generation speed barely moved. Bar chart the four throughput numbers next to the one flag that mattered.

    ~/.claude/projects/-home-thatcher/memory/project_llm_endpoint.md (llm.softwaresoftware.dev, -ub 2048 vs default 512 prefill measurement)
  131. 131
    ThreadSmall · a dayadded 2026-08-28 posted to X · 2026-09-18

    Lose the key, lose the history

    backchannel encrypts everything client-side and the server only ever sees ciphertext and wrapped keys — which means there's no password reset. Identity lives in browser localStorage, per origin, and if it's gone the messages are gone too. That's the tradeoff, stated plainly instead of hidden behind a recovery flow.

    apps/backchannel, ~/.claude/projects/-home-thatcher/memory/project_backchannel.md (ECDH P-256 identity per device, no threads/search/multi-device sync)
  132. 132
    Blog postSmall · a dayadded 2026-08-27

    Three buttons Crestborne deleted, all for the same reason

    In one day the intake screen lost a 'Run mandate screen' button (the screen is continuous, completion drives the stage), a gate-1 checklist list (the term-sheet letter is the artifact, no separate CP list needed), and a 'locked in' status suffix — same rule each time: if the state is already visible, don't ask for a click or spell it out in words.

    apps/crestborne commits bab7e5f (kill the 'Run mandate screen' button), 2b3568a (redesign deal phase band: honest gate state, real decline button), ee10a59 (drop gate-1 CP list — the letter is the artifact), 482f5f7 (drop the caveat note from intake terms panel)
  133. 133
    Blog postMedium · 2–3 daysadded 2026-08-27

    Cell-addressed spreadsheets for agents

    The xl toolkit gives Crestborne's underwriting agents direct cell-address read/write on the actual Excel model instead of round-tripping through markdown dumps or full-file rewrites — what that interface looks like and why coordinates beat regenerating the whole sheet.

    apps/crestborne commit ddc7f6c (xl toolkit: cell-addressed workbook access for agents), 333 insertions
  134. 134
    Demo gifSmall · a dayadded 2026-08-27

    Agents write chart fences, not screenshots

    Deal-chat markdown now supports ```chart fences that render native bar/line charts with a highlighted point via a shared charts.js — an agent explaining a NOI trend just emits a code fence instead of an image or a table.

    apps/crestborne commit ce331bc (deal chat renders markdown; agents embed native charts via chart fences, static/charts.js)
  135. 135
    Blog postSmall · a dayadded 2026-08-27

    Edit one field, requote everything downstream

    Changing a term in Crestborne now writes to a field ledger, forces a requote, and an anchor-mismatch guard blocks the UI from showing a derived number that no longer traces back to its source — the fix for stale numbers is structural, not a warning banner.

    apps/crestborne commits e1d1a1c (requote on change, anchor mismatch guard), 3826541 (revert writes the field ledger and requotes)
  136. 136
    Short (60s)Small · a dayadded 2026-08-27

    Google's 'other contacts' knew an email I didn't save

    A read-only Google Contacts MCP server built in a day surfaced a third, unsaved address for a contact that only existed in Google's auto-collected 'other contacts' — real missing data isn't always a tooling gap.

    mcps/google-contacts-mcp commit d8f7418; memory/reference_contacts_infra.md
  137. 137
    Blog postMedium · 2–3 daysadded 2026-08-26

    Three slots, one gate: why screening had to stop being a score

    Crestborne's gate-1 intake used to grade deals; now it just needs OM, model, and thesis filled in before it spits out instant indicative terms and a binary pass/fail. Walk through why a graded screen was the wrong shape for a go/no-go decision, and what changed in the 1489-line rewrite to make it binary.

    apps/crestborne d82d1b2 (also mirrored in apps/crestborne-staging), 13 files changed
  138. 138
    ThreadSmall · a dayadded 2026-08-26 posted to X · 2026-09-17

    Two ways a new domain breaks your Cloudflare + Resend stack

    Standing up aicotx.com on the existing tunnel/email stack hit two silent failures: cloudflared's cert.pem writes DNS into whatever zone it's bound to (not the domain you name), and Resend bounces sends until you verify the bare domain separately from the DKIM subdomain. Neither error message points at the real cause.

    ~/.claude/projects/-home-thatcher/memory/reference_new_domain_infra_gotchas.md, full repro steps in ~/ai-consulting/aicotx-kb/infrastructure.md
  139. 139
    Short (60s)Small · a dayadded 2026-08-25

    A dead session's scratchpad grew to 24GB and took the desktop app down with it

    claude-desktop was stuck in a GPU crash loop and it looked like a driver bug. The real cause was /tmp being tmpfs on local-yocal — a session scratchpad log had grown to 24GB, eating RAM directly until swap filled. The fix was deleting a file, not touching the GPU stack.

    ~/.claude/projects/-home-thatcher/memory/reference_tmpfs_swap_runaway.md, incident 2026-08-25, path /tmp/claude-1000/-home-thatcher/<session>/scratchpad/cd-final.log
  140. 140
    Short (60s)Small · a dayadded 2026-08-25

    The leaderboard site with no daily texts

    maptapwatch scrapes a family group text for a daily geography game and could easily send a morning podium SMS. It deliberately doesn't — the site is the surface, and the only thing that pages anyone is a new all-time high or low. Fewer notifications was the design goal, not a missing feature.

    ~/.claude/projects/-home-thatcher/memory/project_maptap.md, tools/calwatch/maptapwatch, maptap.softwaresoftware.dev, built 2026-08-25
  141. 141
    Short (60s)Small · a dayadded 2026-08-25

    Messages-for-web doesn't label every text, so the scraper has to remember who spoke last

    The group-text bridge maptapwatch reads only prefixes a sender's name when the sender changes from the previous message. Attribution meant tracking a running "last sender" pointer across the whole scrape, not just parsing each line.

    ~/.claude/projects/-home-thatcher/memory/project_maptap.md, tools/calwatch/maptapwatch/app.rcs_bridge
  142. 142
    Short (60s)Small · a dayadded 2026-08-25

    The marketplace said v2. The install said v1.

    The design-system-v2 plugin source and marketplace had carried version 2.0.0 for weeks, but the locally installed copy was still silently serving the old warm-dark v1 rules — the marketplace listing and the install cache aren't the same source of truth, and only an explicit marketplace update plus a plugin update pulled the fix through.

    ~/.claude/projects/-home-thatcher/memory/project_design_system_v2.md, fixed 2026-08-25, softwaresoftware-design-system@softwaresoftware-plugins
  143. 143
    Blog postMedium · 2–3 daysadded 2026-08-24

    From one seeded user to real auth, in a day

    Crestborne ran on a single seeded account since the 08-17 workshop; commit 3f9dde9 replaces it with username/password accounts, DB-backed sessions, and separate bearer tokens for agents. Walk through why an internal tool needs two distinct identity types — a human clicking around and an agent calling the API on a deal — and what breaks if you conflate them.

    apps/crestborne 3f9dde9 (19 files, 666 insertions), fccf414 (seed directory becomes just thatcher, tests provision their own users)
  144. 144
    ThreadMedium · 2–3 daysadded 2026-08-24

    The loan file learns to answer questions

    904e34c adds an ask tab to the Crestborne deal view — 1,796 lines — that lets you query a specific loan file with field-level context and generate a preapproval letter from it. Show the shape of the feature: what 'field context' means as a retrieval unit smaller than the whole doc, and why that's different from summarizing the deal.

    apps/crestborne 904e34c (13 files, 1796 insertions) — ask tab, field context, preapproval letter
  145. 145
    ThreadSmall · a dayadded 2026-08-24 posted to X · 2026-09-16

    One workshop, eighteen commits: gate language shows up in the nav

    Everything shipped 08-24 traces back to the 08-17 workshop findings doc (ae6899a): nav labels rewritten to match the loan-lifecycle gate terminology from that session (6fb42a8), the daily digest killed and replaced with a systemd timer (ce14c21, 36619bf), loopback bind + reseed opt-in + backup script added as hour-one hardening (2590994). Trace specific findings to specific diffs.

    apps/crestborne ae6899a (workshop findings doc), 6fb42a8, ce14c21, 36619bf, 2590994
  146. 146
    Short (60s)Small · a dayadded 2026-08-24

    The one tell that gave away a forged session

    claude-inbox's forged transcripts passed every check except one: they didn't record the cwd's real git branch, which genuine sessions always carry. Commit 2a0f39b fixes it. A concrete example of what 'looking genuine' actually requires beyond the four-record transcript shape.

    plugins/apps/claude-inbox 2a0f39b (1 file, 19 insertions) — forge: record cwd's real git branch
  147. 147
    Blog postSmall · a dayadded 2026-08-18

    The findings came the day after the demo, not during it

    The HPI demo hit 10/10 anchored fields on the Newmark OM script. The workshop the next day is where the UX gaps actually showed up — pull the specific product/UX findings from the writeup and contrast what the scripted run hid.

    projects/apps/crestborne-staging, commit ad2eff9 (workshop-2026-08-17.md, 273 lines)
  148. 148
    Short (60s)Small · a dayadded 2026-08-17

    217 lines replaced a docker stack

    Catanizer's Catan-probability solver ran as a multi-service docker stack. On 2026-08-16 it became one static HTML file with an SVG board and an in-browser solver — nothing left to deploy or keep alive.

    apps/catanizer, commit 4bb28b6 (2 files, 217 insertions) — 'Rewrite as a single static page: in-browser solver + SVG board; retire the docker stack'
  149. 149
    Blog postMedium · 2–3 daysadded 2026-08-17

    13,879 lines in one day, one demo deadline

    Crestborne OS got rebuilt from a single-file v0 into a full package (notifications, agent console, deal pages, portal) in one day because a Tasksuite demo landed on the calendar — the story is what got cut versus kept under a hard deadline, not the line count itself.

    apps/crestborne, commits f61b7af (25 files, 5668 insertions) + cbaccb7 (68 files, 8211 insertions), both 2026-08-16
  150. 150
    Short (60s)Small · a dayadded 2026-08-17

    Promoting your own site meant not linking to it

    The flagship Hardcore Main reddit post had to ship link-free because r/2007scape's domain whitelist blocks the campaign's own site and its poll host — so the pitch lives entirely in the post body, no URL anywhere.

    personal/hardcore-main-campaign, commit 1e85fc6 'flagship: link-free for r/2007scape whitelist'
  151. 151
    Blog postMedium · 2–3 daysadded 2026-08-17

    Two blackouts, blamed on the GPU. It was swap.

    After two 'the screen went black' incidents got chalked up to the NVIDIA driver, the actual signal was 2G of swap completely full and kwin's main thread stalling under memory pressure — not GPU corruption. memguard now watches PSI and swap directly and talks to Claude sessions to back off before it happens again.

    tools/memguard, commit c3580bc (659 insertions); memory/project_memguard.md root-cause notes
  152. 152
    Short (60s)Small · a dayadded 2026-08-17

    Your engagement metrics count your own replies

    postlab's first metrics pass on X posts counted a thread author's own replies as audience engagement, inflating every number. The fix subtracts your own replies before computing reach.

    tools/postlab, commit eb7076c 'own-reply subtraction'
  153. 153
    Chart + threadSmall · a dayadded 2026-08-17 posted to X · 2026-09-16

    Reload survives. Restart doesn't.

    switchboard's v2 rewrite made conversations a server-side API resource instead of client state — so a browser reload rehydrates full history from the server, but a service restart still clears it. That split is a deliberate boundary, not a bug to fix later.

    switchboard-poc, commit a4fdbe4 'v2.1 de-box experiment + conversation API with full UI parity'; memory/project_switchboard.md API-first note
  154. 154
    Blog postSmall · a dayadded 2026-08-17

    Anchoring a quote the model made up back to the actual PDF

    The agent cites a passage from an OM or intake doc; the server has to find that exact text inside the source file and render a highlight at the right spot. Walk through the fuzzy-match-then-locate step and why quote drift breaks naive substring search.

    apps/crestborne commit 29e150c 'automatic evidence anchoring: intake docs + every later upload (agent cites quotes, server locates + renders)', 15 files/535 insertions
  155. 155
    Short (60s)Small · a dayadded 2026-08-17

    Every document you upload gets anchored now, not just the intake set

    Screen-record uploading a new doc mid-deal and watching an agent citation jump straight to the highlighted line in it — show the before (only intake docs anchored) and after (any later upload too) from today's Crestborne change.

    apps/crestborne commit 29e150c, same feature extended from intake-only to every later upload
  156. 156
    Blog postSmall · a dayadded 2026-08-15

    The mod wasn't unsupported, the build-detection was blind

    BakkesMod's 'unsupported version' popup looked like an anti-cheat ban but was actually two stacked failures: Heroic hides legendary's config outside the wine prefix so the injector couldn't read the Epic build id, and 'inject anyway' then threw the mod into a live EAC session it should never have touched. Root cause took cross-referencing primary sources on RL's April 28 EAC mandate and the mod's sunset/un-sunset before the actual fix (copy, not symlink, the config; use -noeac).

    ~/.claude/projects/-home-thatcher/memory/reference_bakkesmod_setup.md, updated 2026-08-15
  157. 157
    Blog postSmall · a dayadded 2026-08-15

    RCS has no read API, so the phone reads its own notification tray

    There's no way to capture incoming RCS messages on an unrooted Pixel: not the SMS database, not an API. The workaround is termux-notification-list scraping Google Messages notifications into a local SQLite db, exposed to the mesh as messages_recent/search/stats. Sends still go through browser automation on Messages for Web because outgoing RCS leaves no trace at all.

    tools/session-bridge/app/message_capture.py, app/message_query.py, commit 6da1ba3
  158. 158
    Short (60s)Small · a dayadded 2026-08-15

    You can't git clone onto a device that's never seen your key

    Zero-touch mesh provisioning can't assume git access on a fresh phone or container, so the private repo gets tarballed and pushed over ssh instead, then installed with a shared token from ~/.config/session-bridge/token. Verified end to end on a clean Docker container: 6 seconds to join, 8 to self-heal after a kill.

    tools/session-bridge, commits a6f1ecb and a23bdef
  159. 159
    Short (60s)Small · a dayadded 2026-08-15

    Browser tabs an agent opens don't close themselves

    claude-browser-bridge shipped close_session_tabs and a close_tabs_on_session_end option this week, plus close_tab_groups the next day, because agent-driven browsing accumulates tabs with nothing to reap them when the session ends.

    mcps/claude-browser-bridge, commits c3d6e44 and 0cf4283
  160. 160
    Blog poststart hereMedium · 2–3 daysadded 2026-08-15 posted to X · 2026-08-29

    sentinel: I built the alerting layer I actually wanted, then made it a plugin

    Launch post is live on blog.softwaresoftware.dev/posts/sentinel. Follow-ups: the RCS self-text wall (Pixel), the confirm-before-contacting-others rule as the only guardrail on a bypass-permissions agent, and why one morning message beats five.

    plugins/apps/sentinel, sentinel.softwaresoftware.dev, blog post 2026-08-15
  161. 161
    Threadstart hereSmall · a dayadded 2026-08-15

    Text your calendar and it texts back

    Show the real transcript: 'what do I have Tuesday' → agent flags two Austin flights → 'yes look at that' → it finds the Southwest change email and asks before deleting. Reply-to-act with a day-scoped claude -p session.

    sentinel agent.py, session resume
  162. 162
    Short (60s)Small · a dayadded 2026-08-15

    A watcher in three functions

    fetch/alert/brief is enough. Everything else — baseline, dedupe, batching, quiet hours, outbox retry — belongs in an engine, or you rebuild it every time. `sentinel new draftwatch`.

    sentinel/template/*.tmpl
  163. 163
    VideoMedium · 2–3 daysadded 2026-08-15

    Setting up sentinel from zero in 5 minutes (ntfy path)

    /softwaresoftware:install sentinel → /sentinel:setup → ntfy app → first test push → gh watcher live → morning brief. No accounts needed for the demo path.

    skills/setup/SKILL.md
  164. 164
    Blog postMedium · 2–3 daysadded 2026-08-15

    Two ranking systems disagree, so blend them anyway

    draftboard stopped trusting ESPN's VORP alone and now blends it with FantasyPros ECR and live market ADP, with per-position weight knobs and explain/ecr subcommands that show the math behind each suggested pick — how you reconcile two systems that rank the same player 15 spots apart.

    tools/calwatch, commit bc71b26
  165. 165
    Blog postSmall · a dayadded 2026-08-15

    Rehearsing a draft before the real one

    two advisor-driven practice drafts run the day before the live event, specifically to find where the AI recommendation logic breaks under a 45-second clock — producing a findings doc and a game-day runbook instead of debugging live.

    personal/fantasy-football, commit 139c80c
  166. 166
    Short (60s)Small · a dayadded 2026-08-15

    The practice room lied about its settings

    draftboard now diffs the mock draft room's scoring and roster settings against the real league config before trusting any recommendation, because ESPN's practice rooms don't always mirror the live league.

    tools/calwatch, commit 6255d80
  167. 167
    VideoSmall · a dayadded 2026-08-15

    An agent that can only add to the cart

    the walmart_cart mesh agent, triggered from a Termux widget on the phone, drives a signed-in desktop browser over browser-bridge but is scoped to cart operations only — no checkout, no payment surface in reach.

    tools/session-bridge, commit ebf2c57
  168. 168
    Short (60s)Small · a dayadded 2026-08-15

    sentinel remind: a text-in, text-back scheduling primitive

    sentinel's two-way SMS agent picks up a one-shot reminder command (--at/--in/--before) in v1.1.0 — the same reply-to-act loop that drafts messages to other people now also just holds a fact until a clock fires.

    plugins/apps/sentinel, commit 7d7cf64

169–183

Research spin-offs

Each of the 18 research posts (Aug 4–13) becomes a chart, a thread, and a 60-second cut. Numbers already verified.

  1. 169
    Chart + threadstart hereSmall · a day posted to X · 2026-08-16

    Compaction is bimodal

    Restated facts survive /compact 100% of the time; facts that only lived in tool results survive 0%. Zero confabulations in 1,440 graded answers. The fix is a habit — restate to survive — not a plugin.

    research/what-compaction-forgets · ~/ai-consulting/lab/exp-compaction-junk
  2. 170
    Short (60s)Small · a day

    The waste detector found 0.5%

    Everyone assumes agents burn money re-reading files. Measured: $2,287 across 4,083 real sessions, $33 recoverable. The naive detector was 2.8× too high because it counted MCP polling.

    research/tool-use-waste-detection · lab/claude-cost-analytics
  3. 171
    Chart + threadstart hereSmall · a day

    Only 1.24% of tool grants ever get used

    1,053 grants, 165k session-tool pairs; 44% of granted tools never called anywhere; 64% of first uses happen inside one minute. Open with the OpenAI→HF cluster-admin-in-13h story.

    research/agent-blast-radius · lab/blastlens/AUDIT.md
  4. 172
    ThreadSmall · a day posted to X · 2026-08-31

    The crossover that never came

    $ per completed task, not per token: $0.091 (Haiku) → $0.262 (Sonnet 5) → $0.728 (top tier) across 175 runs. The 'premium model gets cheaper because it fails less' story didn't show up.

    research/cost-per-task-not-per-token
  5. 173
    Chart + threadSmall · a day posted to X · 2026-09-01

    Haiku picks a side 58% of the time. Opus 5: never.

    40 seeded KB contradictions × 4 conflict types × 4 models. Small models silently resolve conflicts with full confidence.

    research/kb-conflicts-silent-picks
  6. 174
    Short (60s)Small · a day

    150 tools don't confuse the model — they inflate the bill

    4×4 grid, 772 runs, 5→150 MCP tools: accuracy flat, prompt cost climbs. Small models fail by giving up ('no tool exists'), not by picking wrong.

    research/model-tier-vs-tool-overload · lab/exp-routing-overload
  7. 175
    VideoMedium · 2–3 days

    a11y tree vs screenshots, same task, side by side

    Timelapse of two agents driving the same HR form. Dead heat on success; a11y is 23% cheaper and 2.3× faster; 107 of 112 failures were the environment, not the model.

    research/browser-a11y-vs-screenshots · demo webm in lab/
  8. 176
    Chart + threadSmall · a day posted to X · 2026-09-04

    42.02 vs 42.07

    Function words per 100 in thinking vs prose — identical. Thinking sentences are 4.25 words *longer*. And 90.1% of thinking blocks are unreadable, so CoT oversight is mostly unavailable.

    research/inner-monologue-not-telegraphic
  9. 177
    Threadstart hereSmall · a day

    grep beats RAG — until the store is remote

    recall@5 0.93 lexical vs 0.79 dense on 1,000 planted-fact docs; remote enumeration 130 s vs 3 s with a local mirror. Request-count × provider delay dominates, not the retriever.

    research/grep-vs-rag-retrieval-benchmark · ~/kb-retrieval-experiment
  10. 178
    Image + captionSmall · a day

    The provider latency ladder

    One bar chart: Graph 43 ms → Drive 58 → Notion 90 → Box 105 → SharePoint 116 → Dropbox 120 → Slack 167 ms TTFB. Caption: this is why you mirror first and grep second.

    ~/kb-retrieval-experiment/results/latency_bench.json
  11. 179
    Short (60s)Small · a day

    Three ways Claude deployments bleed money

    Marathon sessions re-billing context, resumes landing just past the cache TTL, expensive models doing mechanical work — from OTEL data. Ends on costlens.

    research/claude-cost-telemetry
  12. 180
    CarouselMedium · 2–3 days

    $111 vs $81 per seat

    The fintech engineering-platform case study as a swipeable verdict matrix (Anthropic 4.3 vs 3.5); the private-marketplace gap is the single highest-weighted difference.

    research/anthropic-vs-openai-case-study-engineering-platform
  13. 181
    ThreadSmall · a day posted to X · 2026-09-05

    Chat, Cowork, Code: three products wearing one app

    No shared permission model, settings path, memory, or audit trail — verified cell by cell.

    research/claude-desktop-chat-vs-cowork-vs-code
  14. 182
    VideoMedium · 2–3 days

    Bedrock takes away exactly one thing

    The two-plane diagram (inference vs distribution never meet); losing claude.ai server-managed settings means MDM ships managed-settings.json instead.

    research/plugin-marketplaces-on-amazon-bedrock
  15. 183
    Image + captionMedium · 2–3 days

    8 experiments, one August

    Cross-post infographic: every headline number from the 18 research posts in one image.

    research.softwaresoftware.dev/index.html

184–189

Drafts to finish

Title-only files in blog/ideas/ — the outlines were written in March; the evidence to back them now exists.

  1. 184
    Blog poststart hereLong · a week posted to X · 2026-08-26

    Context is a pyramid

    Merge three drafts (pyramid / right context at the right time / context rotation) into one context-engineering post, now backed by the compaction and grep-vs-RAG data.

    blog/ideas/context-is-a-pyramid + 2 siblings
  2. 185
    Blog postLong · a week

    Skill cardinality

    How many skills before a plugin should split? Pair the draft with the tool-overload grid and harness-audit's real count: 93 skills, score 34/100.

    blog/ideas/skill-cardinality · toolkits/harness-audit
  3. 186
    Blog poststart hereLong · a week posted to X · 2026-08-27

    A plugin is a pipeline, capabilities are the joints, providers are the swappable pieces

    The ecosystem thesis, finally with proof: 4 frameworks, 20 providers, 26 capabilities, one resolver.

    blog/ideas/ · plugins/CLAUDE.md
  4. 187
    Blog postLong · a week

    Multi-agent architecture patterns

    Role separation, re-derivation passes, reactive daemons vs pollers — drawn from the swarm-methods post plus taskpilot / session-bridge / dispatcher.

    blog/ideas/ · research/agent-swarm-experiments
  5. 188
    Blog postMedium · 2–3 days

    Claude changes the abstraction calculus (and building software is still hard)

    Opinion piece with receipts: 137 repos born, 98 dormant, 34 archived. What got cheap, what didn't.

    blog/ideas/ · gitstats.json
  6. 189
    Blog postMedium · 2–3 days

    State machines, modern use

    approval-channel v3 as the worked example: a human-approval state machine that deliberately does *not* deliver messages.

    blog/ideas/ · providers/approval-channel

190–205

Plugin ecosystem

Resolver, capabilities, frameworks — the softwaresoftware plugin system as engineering stories.

  1. 190
    Blog poststart hereLong · a week posted to X · 2026-08-28

    Eight probes are enough

    A 711-line resolver picks providers for 45 plugins with exactly 8 generic probes (os, shell, binary, port, env, mcp, plugin, file). `binary` lists are AND, everything else is OR; ranking is a 3-key sort with no priority field — on purpose.

    marketplace/softwaresoftware/{resolver.py,probes.py,docs/capability-contracts.md}
  2. 191
    Blog postMedium · 2–3 days

    We deleted the notification capability

    mindframe *required* it May 18; on June 9 the capability and all four providers were archived. Replacement: use whatever tool exists, else write a file. When a contract is too thin to be worth resolving.

    softwaresoftware-marketplace commit 6486825 · mindframe/CLAUDE.md
  3. 192
    Blog postLong · a week

    Six layers, six plugins

    mindframe's Surface / Agent runtime / Event ingress / Knowledge / Mesh / Perception — each a separate plugin bound only by capability.

    frameworks/mindframe/docs/architecture.md
  4. 193
    ThreadMedium · 2–3 days

    151 commits of pivots

    mindframe's commit log as a story: incident-response → knowledge base, Express → FastAPI, Vite → vanilla, three home-page prototypes, watches → agents, share → export.

    git -C frameworks/mindframe log
  5. 194
    ThreadSmall · a day posted to X · 2026-09-06

    A frame is a directory, not a registration

    Any dir with an index.html under ~/.mindframe/frames/ is a live page; a dead agent revives on the next message. Convention beats registry.

    mindframe/docs/delivered-frames.md
  6. 195
    Blog postMedium · 2–3 days

    The uuid7 polyfill that reordered my SSE stream

    Non-monotonic ids within the same millisecond broke the `?since=` cursor and returned the wrong tail. RFC 9562 fix. Small bug, great story.

    mindframe commit 82d1f70
  7. 196
    Videostart hereMedium · 2–3 days

    The reviewer that only sees the disk

    zapframe gates 5 & 6 spawn an independent review agent that can read artifacts but not the conversation — it catches what you'd self-certify past.

    zapframe/skills/create/gates.md
  8. 197
    Blog postLong · a week

    Seven gates from prompt to live URL

    The zapframe pipeline end to end: credential validation, {{VAR}} scan, verify_build / verify_frontend, and 30+ screenshots committed as evidence.

    zapframe/skills/create/*.md · scripts/
  9. 198
    Blog postLong · a week

    SOC 2 gaps in a scaffolded enterprise app, mapped to CC controls

    ironframe's todo.md literally asks for this post: MFA CC6.1, audit immutability CC7.2, alerting CC7.3, backups A1.2 — plus the circular Django migration between organizations and rbac.

    frameworks/ironframe/todo.md · commit ced1964
  10. 199
    Blog postMedium · 2–3 days

    Daemons that outlive their code

    A plugin update leaves the old daemon running. daemon-manager's version-drift check, unix sockets vs Windows named pipes, systemd/launchd/Task Scheduler in one contract.

    providers/daemon-manager/CLAUDE.md
  11. 200
    Blog postSmall · a day

    Rules-only security

    prompt-guard is 247 lines and zero code: detection lives in rules, logging is a pluggable capability. When not writing code is the design.

    providers/prompt-guard
  12. 201
    Blog postMedium · 2–3 days

    Vaults with an approval gate

    Six near-identical ~600-LOC providers: get_summary() masks, secure_fill(approved=True) gates, raw values are never echoed. Plus wallet: a session key that lives only in your shell env.

    providers/*-vault · providers/wallet
  13. 202
    Image + captionSmall · a day

    137 tools, 18 MCP servers, 93 skills — score 34/100

    harness-audit's sample report is a real audit of the author's own workstation. Caption the five clutter signals.

    toolkits/harness-audit/examples/sample-report.md
  14. 203
    Blog postMedium · 2–3 days

    The AI maturity ladder: sell one rung at a time

    L0 shadow AI → L5 orchestrated; the private marketplace is the 2→3 flagship. Consulting framing built from the plugin ecosystem.

    ~/ai-consulting/07-ai-maturity-model.md
  15. 204
    Blog postMedium · 2–3 days

    Design system v1→v2 as a capability

    Warm-dark/gold retired 2026-08-05 for light monochrome and one green accent; 58 sibling sites still on v1 and the `apply` skill went stale — tooling drift is the real story.

    providers/softwaresoftware-design-system · design-system.softwaresoftware.dev
  16. 205
    Demo gifSmall · a day

    Ten screenshots to a checklist

    liteframe's mobile-fixed-*.png iterations became UI-review rules: flex overflow chain, pre-wrap code blocks, nav fade-edge mask.

    frameworks/liteframe/*.png · skills/ui-review

206–219

Agent runtime & mesh

taskpilot, session-bridge, dispatcher, devices-as-MCP, the phone.

  1. 206
    ThreadSmall · a day posted to X · 2026-09-06

    Sandbox $HOME cut agent context 47k→33k. Three weeks later we deleted the sandbox.

    taskpilot 0.9 → 0.12: isolation lost to inheriting the real ~/.claude. Why.

    providers/taskpilot/CHANGELOG.md
  2. 207
    Blog postMedium · 2–3 days

    Pare down to the irreducible core

    taskpilot v0.13 removed cron, mesh spawn, the service reconciler, lifecycle hooks, and a Haiku completion classifier added three weeks earlier. The daemon is reactive: every read reconciles against tmux ground truth.

    taskpilot/CHANGELOG.md 0.13.0
  3. 208
    ThreadSmall · a day posted to X · 2026-09-07

    Claude Code walks up from cwd to $HOME

    The sandbox cwd was the *parent* of HOME, so personal skills leaked into 'isolated' agents. Fix: HOME == cwd.

    taskpilot CHANGELOG 0.9.0
  4. 209
    Image + captionSmall · a day

    Agents never type into tmux

    One diagram: taskpilot → session-bridge :8910 → agent, every message over HTTP. Caption why keystrokes were the wrong interface.

    taskpilot/CLAUDE.md · session-bridge/CLAUDE.md
  5. 210
    Blog postMedium · 2–3 days

    Why the dispatcher polls instead of listening

    On a NAT'd workstation nothing can reach a webhook. Cold start sets the watermark and routes nothing (no agent stampede); cron is just a synthetic event source; static (source,event_type) routing with an LLM fallback.

    providers/dispatcher/CLAUDE.md · app/poller.py
  6. 211
    Blog postMedium · 2–3 days

    session-bridge got smaller every release

    Dropped SSE, cross-host, background discovery; made registration authoritative. Plus the bug list: Zod noise, wedged stdio, squatter overwrites, /proc → ps.

    git -C providers/session-bridge log
  7. 212
    Blog poststart hereLong · a week posted to X · 2026-08-28

    Every Tailscale device is an MCP server

    Zero-touch: tailnet discovery every 15 s, ssh-pushed stdlib agent (Docker container joined in 6 s), binaries→tools catalog. The agent picks a device by its *nature* — mobile for SMS/GPS, desktop for GPU.

    tools/session-bridge experimental/device-mcp · memory project_session_mesh_devices
  8. 213
    Demo gifSmall · a day

    Sending an RCS from a terminal

    Receive via Google Messages notifications (unrooted), send via Messages-for-web driven through the browser bridge on real Brave.

    session-bridge 2026-08-15 commits
  9. 214
    Short (60s)Small · a day

    Text me from my terminal

    curl a natural-language task to the phone on :8788; phone-side Claude runs termux-api and replies through the channel. 20 seconds, no narration needed.

    ~/.claude/rules/phone.md
  10. 215
    VideoMedium · 2–3 days

    Claude Code on a Pixel 7 Pro

    Termux voice agent — 'write for the ear, not the eye' — and the SMS watcher feedback loop that answered its own messages.

    tools/termux/voice-agent
  11. 216
    Blog postMedium · 2–3 days

    A video call where the AI is just another peer

    meet: mesh WebRTC, Web Speech transcription, and the assistant is a Claude session on the session mesh replying with a [TO_MEETING] prefix. No API keys anywhere.

    apps/meet/CLAUDE.md
  12. 217
    Blog postMedium · 2–3 days

    The vault has one writer

    A librarian agent is the sole writer to the knowledge vault; other sessions ask it over the mesh. CATALOG-first answers, bidirectional FK maintenance.

    tools/vault-agent/CLAUDE.md
  13. 218
    ThreadMedium · 2–3 days

    Human-in-the-loop by Slack thread

    gmail-mcp ships 16 tools and deliberately no delete; send requires APPROVE in a Slack thread. finance-mcp needs phone MFA before Plaid calls; beats-mcp holds the DJ key so the agent never sees it.

    mcps/gmail-mcp/.claude/rules/send-approval.md · mcps/finance-mcp
  14. 219
    ThreadSmall · a day posted to X · 2026-09-07

    25 of 36 repos were private: the demo-readiness audit

    Bare `python` in 11 manifests, /home/thatcher leaks, tests firing real telemetry, and the `uv run --directory ${CLAUDE_PLUGIN_ROOT}` fix.

    memory project_softwaresoftware_demo_readiness

220–243

Apps & demos

Things people can click on today — the easiest video/gif material.

  1. 220
    Blog poststart hereSmall · a day

    44.5 billion tokens, $29,555, two users

    tokenboard's live totals as a lens on how much compute a solo dev actually burns: 6,197 sessions, 501k messages.

    apps/tokenboard · /api/totals
  2. 221
    Blog postSmall · a day

    The leaderboard that shrank

    Claude Code prunes transcripts after cleanupPeriodDays, so totals went *down*. Fix: monotonic lifetime counters that absorb only positive deltas.

    apps/tokenboard commit 93f8cb1
  3. 222
    Videostart hereMedium · 2–3 days

    Claude is the DJ

    Tune into beats.softwaresoftware.dev: JSON song → SuperCollider → PipeWire → ffmpeg MP3. Show the state push and the compose decision table.

    apps/beats
  4. 223
    Blog postMedium · 2–3 days

    33 commits in one day: AI-composed lofi in SuperCollider

    The Apr 11 bug ladder: sustained ringing (n_free), sub-bass drone (LeakDC+HPF), stream buffer bloat, channel-by-channel transitions with no fade dip.

    git -C apps/beats log
  5. 224
    ThreadMedium · 2–3 days posted to X · 2026-10-06

    750 songs later

    What an LLM learns to do — and can't — as a composer, from history/*.json; the server snaps out-of-scale notes to key as a safety net.

    apps/beats/history
  6. 225
    Blog postSmall · a day

    Rocket League logs no scores, but it logs your MMR

    Diff PartyLeaderMMR for W/L, reward drops = wins, XP isn't; tracker.gg 403s Python's TLS fingerprint so shell out to curl; MangoHud streams FPS live.

    ~/rocketlogs · rocketlogs.softwaresoftware.dev
  7. 226
    Blog poststart hereMedium · 2–3 days

    Building an app from a meeting transcript, every 10 minutes

    Crestborne's BUILD-LOG: a recurring builder job read a KB updated from the live meeting — v0 08:4x, mandate gate 09:43, RAG screening 10:14, term sheet 10:46, AI intake 11:05.

    apps/crestborne/BUILD-LOG.md
  8. 227
    VideoMedium · 2–3 days

    Provenance derived, not asserted

    Crestborne evidence pane: click a loan-file number, see the deck slide it came from with a bbox computed from pdftotext -bbox-layout geometry.

    apps/crestborne/decks
  9. 228
    Blog postLong · a week

    Your browser, Claude's hands

    59 commits of claude-browser-bridge: one daemon shared by many sessions, tab-group isolation per session, CDP trusted input over synthetic events, PNA preflight, a11y role+name addressing — and the beforeunload dialog that wedges every browser agent.

    mcps/claude-browser-bridge
  10. 229
    Blog postMedium · 2–3 days

    Ubuntu 22.04 → 26.04 in two days for one Wayland bug

    Plasma 5.27 + NVIDIA black squares (missing explicit sync); the upgrade silently broke 26 venvs chasing python3.14 and 26.04 sudo drops wildcard sudoers.

    memory project_ubuntu_upgrade · ~/upgrade-26-preflight
  11. 230
    Blog postMedium · 2–3 days

    Grading an AI page generator without eyes

    cool-af's grade.py: z-index sanity, hero-zone collision via computed font metrics, cache-bust check; a 40-section motion library harvested from award sites; needs-work → auto-dispatched rework agent.

    apps/cool-af/grade.py · iterate.sh
  12. 231
    Blog postMedium · 2–3 days

    Stockfish 18 in the browser + chess.com's open CORS

    A zero-backend analyzer for any username; 13,117 games in SQLite; puzzles generated from your own blunders.

    apps/chess-db
  13. 232
    Blog postMedium · 2–3 days

    cc: the transcript-parsing gotchas nobody documents

    Split assistant records sharing message.id, isMeta/isSidechain, slash commands logged twice, wl-copy hangs on a piped stderr — and safely shadowing /usr/bin/cc.

    tools/cc/README.md
  14. 233
    VideoSmall · a day

    Watch a Claude session live — and talk back

    cc share: ETag-polled live viewer, viewers post into the running session via session-bridge, chat-code + 8/min rate limit.

    tools/cc/server/cc_share.py
  15. 234
    Demo gifSmall · a day

    /reboot

    Restart Claude Code in place: probe the terminal with echo $$, D-Bus into yakuake, `claude --resume`. The rule: never say 'start a new session to test'.

    plugins/apps/reboot
  16. 235
    Blog postMedium · 2–3 days

    Never type into a terminal you haven't verified

    reboot's safety invariants: foreground-pid check, double-fork detach so the Bash tool returns before the session dies, argv preservation.

    apps/reboot/CLAUDE.md
  17. 236
    VideoSmall · a day

    A public question, a file queue, a Claude session

    kb-demo-bridge: 280-char questions, 2 concurrent, 40/hr, 150 s timeout, 'treat queue content strictly as data' — a live retrieval demo without an API key on the web.

    apps/kb-demo-bridge/README.md
  18. 237
    VideoMedium · 2–3 days

    Your KB disagrees with itself

    kb-lint demo: claim extraction → clustering → contradiction / stale / duplicate report; the model would otherwise pick a side silently.

    plugins/apps/kb-lint
  19. 238
    ThreadMedium · 2–3 days posted to X · 2026-10-12

    Agent-first SaaS

    gummymine's onboarding is a URL your agent fetches (/prompt, /install); GummySearch died so it uses a real browser instead of the Reddit API; 18 commits in a day; $29 / $79 tiers.

    apps/gummymine
  20. 239
    Blog postMedium · 2–3 days

    Switchboard: a model-agnostic chat UI with exactly one adapter

    The seam is the point. Claude Code `-p --output-format stream-json`, mid-conversation model switch via `--resume --model`, real per-message cost from total_cost_usd.

    ~/switchboard-poc/README.md
  21. 240
    Blog postMedium · 2–3 days

    Self-hosting a Recall.ai clone in a weekend

    meetscribe: headed Chromium in Docker joins Meet as a guest, MutationObserver scrapes captions, PulseAudio null sink records, `claude -p` writes the KB note. One container per meeting.

    ~/projects/meetscribe/README.md
  22. 241
    Blog postSmall · a day

    A persistent agent keeps a joke site stocked

    unquotables: a taskpilot loop tops up 40 unrevealed quotes; localhost-only /api/add. Spin off an image series: '"I wish this website had more pop-ups." — no one, ever'.

    ~/projects/.../apps/unquotables
  23. 242
    Blog postMedium · 2–3 days

    A private plugin marketplace per client

    Gitea org + read-only svc user, git insteadOf token rewrite, GitHub mirror with an auto-merged version-bump PR as the org-sync trigger — then the pivot: customers never touch Gitea, take an admin seat instead.

    ~/gitea · memory project_marketplace_factory · research/per-customer-plugin-marketplaces
  24. 243
    ThreadMedium · 2–3 days

    Six Stripe-principle reviewers on one repo

    Four research passes → PRINCIPLES.md → api-contract / dx / craft / reliability / change-safety / security-defaults agents, run in parallel, synthesized.

    ~/stripe-review-corpus · ~/.claude/agents

244–251

Post-mortems

34 archived projects. Failures with dates are the most-shared kind of engineering writing.

  1. 244
    Blog poststart hereMedium · 2–3 days posted to X · 2026-08-25

    692 commits, zero users

    keepwatch (692) and sol-template (625) — the pre-agent SaaS era — vs zapframe's 'SaaS from a prompt'. What the commit count bought.

    archive/keepwatch · archive/sol-template
  2. 245
    Blog postMedium · 2–3 days

    I built the phone→desktop relay four times

    claude-relay (SSH file queue, dead sms-watcher) → termux-channel/remote → Kotlin notification-listener app → device MCP on the session mesh.

    archive/claude-relay · archive/termux-* · android-apps/softwaresoftware-relay
  3. 246
    Blog postMedium · 2–3 days

    Two vault migrations in six weeks

    vault-v1 → vault-personal v2 (122 commits) → mindframe-vault-attempt (73 repos in 2 days, abandoned) → hq-kb. What a KB schema actually needs.

    archive/vault-* · archive/mindframe-vault-attempt-2026-05-17
  4. 247
    Blog postMedium · 2–3 days

    When the dashboard became a layer

    taskboard deprecated 2026-06-06 — the 'pull path / eyes' framing lost to mindframe's Surface. home-taskboard: 84 commits on a dashboard nobody else will see.

    archive/taskboard/README.md · tools/home-taskboard/wiki.md
  5. 248
    ThreadSmall · a day posted to X · 2026-09-08

    Four notification plugins, one capability

    notify-email / linux / slack / windows collapsed into providers — the cleanest case for capability contracts.

    archive/notify-*
  6. 249
    ThreadSmall · a day posted to X · 2026-09-08

    One-commit ideas

    orecast → gummymine, AgentShield → prompt-guard + the blast-radius study, seedcast, outreach-pipeline. What a one-day scaffold teaches.

    archive/orecast · archive/claude-security · archive/seedcast
  7. 250
    Blog postSmall · a day

    Seven dashboards in two days from one serve() call

    telemetry / daemons / slack / github / docker / vault dashboards from a systems.json + packs pattern — then all abandoned. Frameworks that generate faster than you can use.

    ~/projects/*-dashboard
  8. 251
    Blog postMedium · 2–3 days

    98 of my 150 repos are dead, and that's the point

    Abandonment as a feature of experimentation; the ~10 survivors and what they share.

    gitstats.json abandoned list

252–260

By the numbers

Charts from a re-derived git census (2,925 Thatcher-authored commits, 150 repos, bots and clones filtered).

  1. 252
    Chart + threadstart hereSmall · a day

    9 months, 2,925 commits, 150 repos

    Monthly curve, work vs personal stacked: 89 → 1,177 (April = 40%) → 53 (July, new job). A mountain, not a plateau.

    scratchpad/gitstats.json by_month
  2. 253
    Chart + threadstart hereSmall · a day

    The month I stopped writing commits alone

    Claude co-author share by month, 0% → 82%; 46% overall, 57% since March. A clean before/after marker for leaving the day job.

    gitstats.json claude_by_month
  3. 254
    ThreadSmall · a day posted to X · 2026-09-09

    The day I shipped 200 commits across 48 repos

    Apr 6 2026: five repos born (gummymine, ironframe, irontest, termux-channel, ironframe site). Top 5 days = 26% of the year.

    gitstats.json busiest_days
  4. 255
    Image + captionMedium · 2–3 days

    Birth order of the ecosystem

    137 repos in 8 months on one timeline: star-ext (Jan 6) → Mar 23 big bang (9 repos) → switchboard-poc (Aug 15).

    gitstats.json birth_order
  5. 256
    Chart + threadSmall · a day posted to X · 2026-09-09

    The Big Bang: 92 repos in 26 days

    Daily repo births Mar 23 – Apr 17.

    gitstats.json
  6. 257
    Chart + threadSmall · a day posted to X · 2026-09-11

    When I actually code

    Hour × weekday heatmap: 10 am and 1 pm peaks, 9.7% at night, 13% weekends — and Wednesday is dead (212 vs 671 Monday). Ask the audience why.

    gitstats.json by_hour, by_dow
  7. 258
    Chart + threadSmall · a day posted to X · 2026-09-12

    Top 15 repos, colored by Claude share

    The AI-heaviest repos are the frameworks: mindframe 82%, taskpilot 83%, cool-af 90%; the Obsidian vault and work repos ≈ 0%.

    gitstats.json top_by_commits
  8. 259
    ThreadSmall · a day posted to X · 2026-09-14

    Lines of code lie

    6.2M raw lines added vs 754k after removing two vendored 'initial commit' dumps (one was 5.07M). Always show the cleaned number.

    gitstats.json biggest_commits
  9. 260
    Image + captionMedium · 2–3 days

    The census

    93 repos, 63 subdomains on one desktop through Cloudflare Tunnel, 34 killed (37%), 4 frameworks, 20 providers, 45 marketplace plugins, 18 research posts in 10 days.

    projects/* · staticsites/

261–268

Methods & house rules

How the work is done — the meta-content that travels furthest.

  1. 261
    Blog poststart hereMedium · 2–3 days posted to X · 2026-08-26

    Never publish a number an agent gave you

    Every re-derivation caught an error: 5× → 2.84×, a '$2.57' reproduced from nothing, '192/192' that was mostly billed refusals. If agent output isn't persisted, you can't attribute the claim.

    ~/ai-consulting/ideas.md · memory project_research_blog_pipeline
  2. 262
    ThreadSmall · a day posted to X · 2026-09-14

    Five hypotheses my agent swarm inverted

    KB conflicts (0% silent picks in the pilot), tool overload (flat), waste (0.5%), telegraphic CoT (no), junk-filter-for-free (no). Lead with the inversion — it's the credibility asset.

    research/agent-swarm-experiments · ~/ai-consulting/lab
  3. 263
    Blog postMedium · 2–3 days

    I forged Claude Code session files to run controlled experiments

    Copy a .jsonl to a new uuid, edit the history, `claude -p --resume`; the model reads the forged past and a real /compact runs headless. 120 runs for $12.42.

    memory reference_forged_session_harness · lab/exp-compaction-junk/scripts
  4. 264
    ThreadSmall · a day posted to X · 2026-09-15

    Contaminated data gives confident wrong answers

    21 'per-hole' game files were byte-identical copies; the analysis came out clean and wrong. md5 your inputs before you hand them to an agent.

    ~/wsr-golf-re · memory project_wsr_golf
  5. 265
    Blog postLong · a week

    The 13-rung bisect

    AI-assisted reverse engineering of a Wii golf hole: every shot 'instant OOB', a false-positive detector nearly inverted a rung, the ball flew exactly backwards per 60 Hz RAM reads. Root cause: a full-map cameralock floor.

    ~/wsr-golf-re/NOTES.md · tools/bisect.py
  6. 266
    Blog postMedium · 2–3 days

    The session-limit blowout

    2026-08-05: four concurrent experiment grids hit the limit, credit exhaustion killed four writers mid-render, and an agent's `pkill -f uvicorn` took out the dispatcher. Rules that came out of it: limit-aware sequential orchestration, port-scoped kills.

    ~/ai-consulting/ideas.md ops notes
  7. 267
    ThreadMedium · 2–3 days

    My Claude Code setup

    21 plugins across 7 marketplaces, 9 MCPs, an audit-log hook for tracked CLIs, a rule that auto-pushes CLAUDE.md, a memory dir as project journal, and a laptop that's a read-only Syncthing satellite with hourly config push.

    ~/.claude/settings.json · hooks/audit-log.sh · ~/.local/bin/claude-config-push
  8. 268
    ThreadSmall · a day posted to X · 2026-09-15

    DNS must always have a fallback

    Pi-hole over Tailscale served the whole house; one reboot left Tailscale stopped, Pi-hole couldn't bind, every device lost DNS. Ordering + public fallback.

    memory reference_pihole_dns · ~/pihole

Effort

Small — a day; the data or demo already exists. Medium — two to three days; needs a re-derivation pass or a recorded demo. Long — a week; a real essay with diagrams.

Evidence

Paths are relative to ~/projects/softwaresoftware/projects/ unless they start with ~ or name a memory file. “research/” = staticsites/research.softwaresoftware.dev/posts/.

House rule

Any number quoted here came from an agent pass over the repos. Re-derive before publishing — that rule has caught an error every single time it was applied.