postlab · softwaresoftware.dev · @ThatcherThorn

Ideas in, posts out, data back in

postlab takes the next idea from the content schedule, drafts several candidates with a reviewer in the loop, posts the winner to X, then measures what happened at fixed ages and rewrites its own playbook from the numbers. This account is the low-stakes test bed: the point is signal, not reach.

64posted · 42 rejected/failed
13median views @24h
12followers
59playbook rewrites
$236.59agent spend total

Pipeline

How a post gets made

Every stage's prompt and raw output is kept on disk. Numbers in a post must be traceable to the idea's evidence; the drafter and reviewer both have read-only access to the files and are told to check.

content schedule ──▶ pick (starred, X-native formats, small effort first) │ ▼ draft 3 candidates ──▶ review (7 criteria, hard_fail on unverifiable numbers) ──▶ revise ──▶ review … (≤1 rounds) │ │ │ accept ≥ 7.5 ────────────────────────────┤ below 6.5 → rejected ▼ ▼ hard checks (≤280 chars, no placeholders, no banned phrases) ──▶ post to X via the browser bridge ──▶ mark idea "posted" in ideas.json │ ▼ metric snapshots at 1h, 3h, 6h, 12h, 24h, 48h, 72h, 168h, 336h ──▶ learn: stats by hook/form/length/time + reply texts ──▶ LEARNINGS.md ──▶ next draft

Playbook

What the data says so far

Rewritten by the learn step whenever new posts cross 24 hours. Every bullet carries its n; below n=5 it is a signal, not a rule. Fed verbatim to the drafter and the reviewer.

LEARNINGS: @ThatcherThorn on X

> Two eras. Old era = id1 through id116 (to 2026-10-13). The owner rejected that voice as robotic and too full of private references. New era = id117 onward (from 2026-10-14). Old-era numbers are a baseline only, not a style guide. Never pool the two eras.

> Data as of 2026-10-15. 64 posts published. 61 have views@24h: 60 old era plus id117. id118 has only a 12.6h capture. Slots are 09:00 and 16:00 local.

Confirmed (n≥5, old era)

  • ≥20 views at 6h means a breakout (n=6, 2026-08-25→2026-10-12). All 6 reached ≥41@24h: id18 161→182, id53 99→105, id43 26→56, id24 30→44, id42 30→41, id113 21→44. No post under 20@6h has passed 33@24h (n=52). id117 fits the rule in the new era too (40→195, n=1).
  • A 6h capture of ≥8 sets a floor (n=27). All 27 reached ≥12@24h. The 31 posts at ≤7@6h ended anywhere from 4 to 19. id118 ([email protected], [email protected]) is the next check on this.
  • The old-era median at 24h is 13 (n=60). The last five were 8, 5, 44, 22 and 11, a median of 11. id18 (182) and id53 (105) account for most of the total views.
  • Hook type made no difference once outliers are removed (old era). Contrarian n=12, median 14.5, carried by id18 and id53. Number n=24, median 14. Story n=13, median 12. Observation (incl. id117) n=11, median 15.
  • Old-era engagement was close to zero (n=62). Lifetime: 9 likes, 9 replies, 0 reposts, 0 bookmarks.
  • Views keep growing after 24h, by varying amounts. 72h/24h ratios ran from 1.27 to 2.1. id63 went 24→101@337h. Only compare posts at the same age.
  • H1–H15 are closed. Don't reopen them. Every test that needed an outside action died (n=5: H4, H7, H8, H11, H15).

Early signals

  • The first new-era post broke out (n=1). id117 (2026-10-14, 3-tweet thread): 195 views, 2 likes, 7 replies and 1 repost at 24.9h. That's the top post ever. It has more replies than the whole old era (9 across 62 posts) and the account's first repost. It grew about 5x from 6h to 24h; old breakouts grew 1.1–2x. One post, so it is not a trend.
  • id118 looks like a normal post (n=1). It's a 2-tweet Playwright web-push tip at [email protected] and [email protected]. If it lands near the old median, id117 is carrying the new era so far.
  • Threads: no read yet. All thread posts: n=3, median 24 (id29 20, id37 24, id117 195). Both new-era posts are threads, so the voice change and the form are confounded.
  • Opening with the wrong suspect: mixed results (retro n=3). id113 = 44, id71 = 9, id62 = 7. id113 accounts for all of the upside.
  • Hour and weekday look like noise (old era). Morning median 13.5 (n=32), midday 11 (n=29).

What people want (from replies)

  • Blast radius is the topic that draws replies, in both eras. Old era: 4 of 7 text replies were about scope or reach. New era: all 5 text replies on id117 were too.

- id117 (2026-10-14) @alekdobrohotov: *"the group chat is basically your sudoers file"*

- id117 @automater_ai: *"Visible to everyone, obeys only the owner should be the default, not a feature."*

- id117 @gzzonkugood: *"the chat itself becomes the permission boundary… a throwaway container per session feels like the bare minimum… has anyone actually tried poking at it yet?"*

- id24 (2026-08-28) @termalinapp: *"do you scope which nodes it touches, or is online == fair game"*

  • People share their own sandboxing setups and want to compare. id117 @inc_ongi: *"i only run skip-permissions inside a container with no creds mounted, anything touching the real machine still goes through approvals"*. Others suggested a throwaway container (id117) and a run-level manifest (id42).
  • Readers want to see it attacked. @gzzonkugood asked whether anyone has tried to break it (n=1).
  • The boundary topic alone isn't enough (old era, n=5). The H13 posts were about lines in my own private tools and got 0 of 5 replies. id117 framed the risk around a setup readers have themselves: a coding agent in a shared chat. That difference is untested (n=1).
  • Some replies are noise. id117 @federicodonaton ended with *"let's connect"*. id113 @Juuuuuddi: *"behind the curve"*. Don't count those as demand.

Avoid

  • Tests that need anything beyond the post text (n=5 blocked).
  • Closing questions as reply bait. H14 got 0 of 4.
  • @mentioning tool accounts for reach. H12 got 4, 10 and 5 views.
  • Predicting 24h from a 6h capture of ≤7 (n=31, range 4–19).
  • Mixing capture ages, using means, or mixing eras. Several "72h" captures (id90, id114) were really about 48.7h.
  • Letting one outlier set the direction. Re-check every new-era claim with id117 removed.
  • Treating no replies before 72h as final. id24's reply came between 24h and 72h.

Next hypothesis

H16 (opened 2026-10-14; 2 of 8 placed, 1 resolved): the voice reset gets more reach. New-era posts are casual, pass the stranger test, and cover topics people building with AI already care about.

  • Resolved: id117 = [email protected]. Pending: id118 ([email protected]).
  • Test: median views@24h of the first 8 new-era posts vs the old-era median of 13 (n=60). Supported if the median is ≥20 and stays ≥20 with id117 dropped. Falsified if it's ≤13. Anything in between is inconclusive.
  • Secondary: log replies at true 72h for each post.
  • No format template. Length, opener and form are free.

Signal

Views at 24 hours, by dimension

Median views 24h after posting (n per bucket). One hue: these are magnitudes of one measure, not categories to tell apart. Tables under each chart.

Hook type

observation n=1115
contrarian n=1214.5
number n=2414
story n=1312
howto n=111
table
nviews@24h (median)eng % (median)
contrarian1214.50.0
story13120.0
number2414.00.0
observation11150.0
howto1110.0

Form

thread n=324
single n=5812.5
table
nviews@24h (median)eng % (median)
single5812.50.0
thread3240.0

Length

>280 (thread) n=324
141–280 n=5613
≤140 n=29
table
nviews@24h (median)eng % (median)
141–2805613.00.0
>280 (thread)3240.0
≤14029.04.545

Time of day

morning 5–11 n=3213.5
midday 12–16 n=2911
table
nviews@24h (median)eng % (median)
midday 12–1629110.0
morning 5–113213.50.0

Weekday

Mon n=920
Sat n=619
Fri n=916
Thu n=714
Tue n=1212.5
Sun n=710
Wed n=118
table
nviews@24h (median)eng % (median)
Tue1212.50.0
Wed1180.0
Thu7140.0
Fri9160.0
Sat619.00.0
Mon9200.0
Sun7100.0

Source format

blog n=630.5
long n=126
thread n=3611.5
chart n=1811.5
table
nviews@24h (median)eng % (median)
blog630.50.0
long1260.0
thread3611.50.0
chart1811.50.0

Posts · 119

Everything the pipeline produced

Newest first, including rejects. Sparkline = views over the snapshot ages; the table beside it has the exact counts.

  1. #119failedhowtothreadscore 80 rounds3 tweets2026-10-15 09:38

    A Review tab built around the terms the agent moves

    building a loan underwriting tool where an AI agent can edit the deal file. the hard part was deciding which of its edits wait for a person and which can just land.

    anything that would change what the borrower was quoted sits as a proposal. nothing hits the file until an underwriter approves, and they can take some of the changes and drop the rest.

    softer stuff, like a lease-up assumption that only feeds the what-if scenarios, the agent applies right away. it still shows up in the review queue with keep and undo buttons, since nobody's looked at it yet.

    · #1 is postable as-is. It's the most human of the three, passes the stranger test, every claim matches review.py, and it lands on the agent-approval-boundary topic, the only topic that has drawn replies on this account. #
  2. #118postedobservationthreadscore 71 rounds2 tweets2026-10-14 22:47

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

    playwright's bundled chromium can't test web push. subscribing fails with "Registration failed - permission denied" because it ships without google's push service keys.

    real chrome works. point playwright at /opt/google/chrome/chrome with a persistent profile, and allow notifications and push_messaging for your origin in Default/Preferences. headless, the subscription can take about a minute to show up, so don't give up after 5 seconds.

    x.com/ThatcherThorn/status/2110502894533509351 · This is the only candidate and it's close. It's accurate, passes the stranger test and has a useful, specific payload. It needs a small edit before posting: connect it to the AI-agent audience, which is the H16 relevance
    ageviewslikesrepliesrepostsbookmarks
    1.62h10000
    3.59h50000
    6.55h80000
    12.59h90000
  3. #117postedobservationthreadscore 71 rounds3 tweetstests hypothesis2026-10-14 15:33

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

    if teammates can message your coding agent in a shared chat, they basically have a shell on your laptop. mine runs Claude Code with --dangerously-skip-permissions because otherwise it just sits there asking me to approve things. anyone who can talk to it gets that too.

    so in the team chat app i'm building, nobody's agent gets shared. everyone connects their own machine with their own key. you can @ your agent in a channel and everyone sees the reply, but it only ever takes orders from you.

    downside is you can't lend a teammate your agent. i'm ok with that. sharing one would mean handing them the same access i have.

    x.com/ThatcherThorn/status/2110393584524665334 · Only one candidate, and it's close. The hook is true and specific, I verified the flag in connector.py:113, and a stranger can follow it. One fix is left before posting. Tweet 3 restates tweet 1 and closes on a kicker. F
    ageviewslikesrepliesrepostsbookmarks
    1.85h282600
    3.8h382700
    6.8h402700
    12.86h482700
    24.86h1952710
    @alekdobrohotov yeah at that point the group chat is basically your sudoers file
    @automater_ai Right call. An agent that takes orders from the whole channel isn't a teammate, it's a vending machine that dispenses shell access to whoever asks nicely. Visible to everyone, obeys only the owner should be the default, not a feature. #Agen
    @federicodonaton A shared chat plus skip-permissions turns every teammate into a sudo user let's connect
    @gzzonkugood honestly the scary bit is that the chat itself becomes the permission boundary. whoever's in the channel is effectively root. a throwaway container per session feels like the bare minimum here. has anyone actually tried poking at it yet?
    @inc_ongi yeah this is the part people skip. i only run skip-permissions inside a container with no creds mounted, anything touching the real machine still goes through approvals
  4. #116postednumbersinglescore 71 rounds1 tweets2026-10-13 22:44

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

    12 seconds: how long a friend's chocolate tour lasted on our Costa Rica itinerary. Anyone on the trip can ask the site's agent to edit the itinerary. Every edit is a git commit ending in "(asked by Sarah)". Undo is one revert. git blame, for people who've never heard of git.

    x.com/ThatcherThorn/status/2110139540702986498 · This is the only candidate. The facts are verified and the shape is good, with a cheap fix needed. The 12-second hook implies a story (the friend's tour got killed) that the evidence doesn't support. The revert was almos
    ageviewslikesrepliesrepostsbookmarks
    1.67h10000
    3.62h10000
    6.62h10000
    12.62h10000
    24.66h110000
  5. #115failedstorythreadscore 71 rounds4 tweets2026-10-13 09:43

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

    My Costa Rica trip site takes edits from anyone in the group through a terminal. An agent makes the change; the backend commits it. Every commit message ends with who asked, like "(asked by Thatcher)". Sarah's chocolate-tour request was reverted 12 seconds after it landed.

    The log reads like the trip's change history: - Swap Manuel Antonio for Playa Hermosa, Mar 2-5 - Fix map routes, pins and sleep link after Hermosa swap - Add 2 Playa Hermosa stay options - Add Playa Hermosa eats and 3 stays - Add map pins for 3 Hermosa eats and Marea Brava

    Line two came 105 seconds later: I asked it to fix what the swap missed. The swap changed the itinerary but left the routes and pins on the old beach. Five agent commits in under 13 minutes, each its own undo point.

    Undo is a git revert behind /undo. The tour went in and came back out 12 seconds apart, and the revert message keeps the name. Caveat: I'm the author on every commit, so git blame says me. The name in the message is the only record of who asked.

    · This is the only candidate, and it is accurate (verified against the reflog) and specific. It is not postable as-is for two reasons. First, it publishes a named friend together with exact trip dates and the location. Sec
  6. #114postedobservationsinglescore 71 rounds1 tweets2026-10-12 22:36

    Agent-first SaaS

    One line from the setup doc my Reddit research app serves to AI agents: "Do NOT ask the user to copy-paste the key. You have browser access — use it." The agent opens the settings page, reads the API key and writes itself a skill file. The human signs up and names a topic.

    x.com/ThatcherThorn/status/2109775292453806572 · This is the only candidate, and the copy is close to ready. Every claim checks out against install/content.ts, it fits within 280 characters, and it uses a concrete artifact as the hook instead of an adjective. I'm not a
    ageviewslikesrepliesrepostsbookmarks
    1.79h50000
    3.79h130000
    6.79h140000
    12.74h190000
    24.74h220000
    48.78h250000
  7. #113postednumbersinglescore 71 rounds1 tweetstests hypothesis2026-10-12 15:37

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

    I blamed Claude for eating my RAM. It was the MCP servers: every headless runner spawned its own stdio copy of all 11. About 1 GB per session, about 9 GB with 9 running. Now each server runs once as a systemd HTTP service on its own port, and sessions connect by URL.

    x.com/ThatcherThorn/status/2109669808514179476 · The copy is close to postable: specific numbers that trace to the source, a clear diagnosis, and a clean engineering voice. It can't go out as-is for two reasons. The fix line overstates the change: 9 of the 11 were move
    ageviewslikesrepliesrepostsbookmarks
    1.75h50000
    3.8h130100
    6.77h210100
    12.76h340100
    24.77h440100
    48.75h460100
    72.79h460100
    @Juuuuuddi behind the curve
  8. #112postedstorysinglescore 71 rounds1 tweets2026-10-11 22:40

    Four security headers added in 17 lines before a public promote

    Cloudflare's edge served my lending app's term-sheet PDFs for four hours to anyone with the URL. It caches by file extension. Fix: a middleware setting private, no-store. Before prod it added framing, nosniff, referrer, plus HSTS only on the public host so tailnet isn't pinned.

    x.com/ThatcherThorn/status/2109413847014703409 · This is the only candidate, and it's close. The hook is true and specific: Cloudflare cached term-sheet PDFs by file extension and served them to anyone for four hours, and main.py:57-60 backs that up. The second paragra
    ageviewslikesrepliesrepostsbookmarks
    1.72h10000
    3.68h30000
    6.71h30000
    12.7h30000
    24.7h50000
    48.68h70000
    72.72h90000
  9. #111rejectedobservationsinglescore 61 rounds1 tweets2026-10-11 09:36

    Four security headers added in 17 lines before a public promote

    The textbook X-Frame-Options value is DENY. My lending app ships SAMEORIGIN. Its document viewer frames the app's own pages, so DENY would break the viewer. SAMEORIGIN still stops any other site from framing a deal page. The reason sits in a code comment next to the header.

    · This is the only candidate, and every claim in it is accurate. The hook is good: the post goes against the standard advice on purpose, and line one names the exact value. It loses its last line to filler and drops the HS
  10. #110failedobservationthreadscore 71 rounds4 tweets2026-10-10 16:37

    Four security headers added in 17 lines before a public promote

    My app sends HSTS only when the Host header matches the public URL. Any other hostname the same instance answers on (tailnet, localhost) gets nothing, so no browser pins it to HTTPS for a year. It's one of four headers I added before the prod promote. The other three:

    2/ X-Frame-Options: SAMEORIGIN, not DENY. The app's document viewer frames its own pages, so DENY would break it. Other sites still can't frame it.

    3/ X-Content-Type-Options: nosniff. A file served as text stays text; the browser doesn't guess HTML or script. Referrer-Policy: same-origin. Deal pages are /deal/<id>. An outside link no longer sends that URL along.

    4/ Same middleware stamps Cache-Control: private, no-store. Cloudflare caches by file extension, and it had served signed-in term-sheet PDFs from the edge to anyone for four hours. All four headers use setdefault, so a route that sets its own value keeps it.

    · There's only one candidate. It's accurate, specific and in the house voice. Post it after three small edits: state the HSTS failure mode in tweet 1, clear up the 'it' and 'all four' ambiguity in tweet 4, and tighten the
  11. #109postednumbersinglescore 6.51 rounds1 tweetstests hypothesis2026-10-10 15:43

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

    Four commits in 160 seconds on one feature: a gate, a flag, a revert, and a revert of the revert. The lines I reverted as a mistake were the flag's guard. When title work should start isn't settled, so it ships parked. Where do your unsettled product rules live: flag or branch?

    x.com/ThatcherThorn/status/2108946608625013103 · This is the only candidate, and every fact in it is accurate and verified. The hook works and the closing question fits H14. It is held back by the middle sentence, which doesn't say what the revert would have broken, pl
    ageviewslikesrepliesrepostsbookmarks
    1.69h20000
    3.61h20000
    6.69h20000
    12.61h70000
    24.65h80000
    48.64h90000
    72.66h141000
  12. #108rejectedstorysinglescore 61 rounds1 tweetstests hypothesis2026-10-09 16:34

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

    Four commits in 160s on one rule in a real-estate deal flow: Title waits for underwriting sign-off. Title order parked behind a flag, off. Revert two lines I'd committed by mistake. Restore them, 18s later: they were the guard. Unsettled rules: off flag on main, or a branch?

    · This is the only candidate and it's close. Every number checks out against the reflog and the closing question is a valid H14 placement. Two problems block posting it as-is. Line 4 says the lines were a mistake when the
  13. #107postedobservationsinglescore 71 rounds1 tweetstests hypothesis2026-10-09 15:38

    42 seconds to 3.6: precomputing bounding boxes for place stats

    42 s to 3.6 s on one DuckDB query. Each place's bounding box is computed once; a lat/lon BETWEEN runs first, so the ST_Contains join only sees pings inside the box. When your point-in-polygon joins get slow, do you reach for an R-tree index or hand-roll a bbox prefilter?

    x.com/ThatcherThorn/status/2108582779911020685 · Candidate 0 can be posted as-is. Every claim traces to project_apollo.md:33 and apollo/core/places.py:5,175-176. It's a valid H14 slot on a non-boundary subject, and the closing question is one a practitioner can answer.
    ageviewslikesrepliesrepostsbookmarks
    1.78h80000
    3.72h80000
    6.75h110000
    12.79h140000
    24.73h150000
    48.74h180000
    72.74h190000
  14. #106postednumbersinglescore 80 rounds1 tweetstests hypothesis2026-10-08 22:46

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

    DuckDB's ST_Distance_Sphere wants ST_Point(lat, lon). Every other spatial function there wants (lon, lat). My v1 passed (lon, lat). Its distances ran 30–50% off at 48–56°N. Now a test asserts one known distance. What in your geo pipeline would catch a swapped axis?

    x.com/ThatcherThorn/status/2108328296492798329 · Go with candidate 0. It's accurate (I checked L21 at DESIGN.md:281), it's specific, and it's the only candidate that keeps H14 running. Its question ending is on a new subject (geo pipelines, not boundaries), so it also
    ageviewslikesrepliesrepostsbookmarks
    1.58h40000
    3.61h70000
    6.64h70000
    12.62h70000
    24.62h70000
    48.56h70000
    72.64h90000
  15. #105postedstorysinglescore 81 rounds1 tweetstests hypothesis2026-10-08 15:35

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

    My lending engine can't decline. Red meant auto-declined. The client: "Let's not have a decline… just review." A miss goes to an underwriter, even a hard policy breach. Only a person can say no. Does your scoring model ever reject on its own, or does every red go to a human?

    x.com/ThatcherThorn/status/2108219804582916283 · This one is accurate and on-hypothesis, and the voice is clean. Post it. The only real flaw is that line 2 doesn't name the thing that was red. If you have room, fix that without going over 280 characters. Otherwise it c
    ageviewslikesrepliesrepostsbookmarks
    2.8h10000
    3.75h30000
    6.8h30000
    12.83h30000
    24.8h40000
    48.76h40000
    72.78h50000
    168.82h60000
  16. #104failedcontrarianthreadscore 71 rounds3 tweetstests hypothesis2026-10-07 16:33

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

    1/ My lending app's rules engine can no longer decline a deal. After a client walkthrough, the first screen has two outcomes: green or referred. Green gets indicative terms in real time. Referred goes to an underwriter. Only a person can decline, after review.

    2/ The same commit changed two more rules. LTV is computed on post-improvement value. Not purchase price, not exit value. A DSCR under the 1.25x floor is no longer a red. It's a condition on the quote: 12 months to cure (24 selectable), or a remedy such as a cash reserve.

    3/ None of the three were bugs. The code did what I'd decided. Each was a lending call I'd encoded as a hard threshold. A 56-minute walkthrough with the lender's team changed all three. Does your rules engine ever decline on its own, or does a person always make that call?

    · The only candidate is accurate, specific and hypothesis-compliant. It needs two or three wording fixes to read cleanly for someone outside lending. It's close to postable.
  17. #103postednumbersinglescore 6.51 rounds1 tweetstests hypothesis2026-10-07 15:40

    Crawling a county parcel site 200 parcels at a time

    A Chromium renderer hit 21 GB 4,000 parcels into my El Paso County crawl. The single-page app leaks memory on every navigation. New browser contexts still crept. Fix: restart the whole browser every 200 parcels. Scope: only parcels a water-rights site sits on, not the county.

    x.com/ThatcherThorn/status/2107858563473523025 · This is the only candidate. It is accurate and hooks well, but don't post it as written. Two numbers are stated more exactly than the source supports, and the boundary line, which is what makes this post count for H13, i
    ageviewslikesrepliesrepostsbookmarks
    1.68h30000
    3.72h30000
    6.75h30000
    12.68h40000
    24.74h70000
    48.72h90000
    72.69h100000
    168.7h140000
  18. #102postedcontrariansinglescore 71 rounds1 tweetstests hypothesis2026-10-06 22:44

    750 songs later

    Claude writes every note on my lofi radio stream. It doesn't get the final say on pitch. The server snaps off-key notes to the nearest scale note. The hole: the net only runs if a song declares a key. The prompt requires one. 11 of 750 skipped it and played exactly as written.

    x.com/ThatcherThorn/status/2107602938692796695 · Post it. It's accurate, specific and on-subject for H13: it names a boundary and admits where it leaks. At 279 weighted characters it fits in one tweet with nothing to cut. The edits below are optional fixes for small ac
    ageviewslikesrepliesrepostsbookmarks
    1.68h20000
    3.66h30000
    6.68h30000
    12.61h40000
    24.67h40000
    48.65h50000
    72.66h60000
    168.61h90000
  19. #101postedcontrariansinglescore 71 rounds1 tweetstests hypothesis2026-10-06 15:34

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

    Whisper decides when each word of my captions appears. It doesn't decide what the word says. faster-whisper transcribes my TTS narration only for word timestamps. The text on screen comes from the script. A misheard word can shift a timing, but it can't put a typo on screen.

    x.com/ThatcherThorn/status/2107494712877924358 · This is the only candidate, and it's postable. It's accurate, has a direct voice, makes a real point about where the model's control ends, and fits H13 well enough to count as a borderline placement. It's thinner than it
    ageviewslikesrepliesrepostsbookmarks
    1.85h10000
    3.78h10000
    6.82h10000
    12.77h40000
    24.8h40000
    48.83h50000
    72.82h50000
    168.81h90000
  20. #100postingobservationsinglescore 71 rounds1 tweetstests hypothesis2026-10-05 16:33

    Human-in-the-loop by Slack thread

    My agent is told to send email only after I reply APPROVE in a Slack thread. The rule: wait for a reply containing "approve" or "reject". "Disapprove" contains "approve". send_email checks nothing. The gate is a prompt. Tighten the match, or move the check into send_email?

    · This is the only candidate, and it's close. The claim is true and verified, specific, and squarely on-subject for H13. It isn't ready to post as-is: the most surprising fact sits in line 3, one claim overreaches ('checks
  21. #099postingobservationsinglescore 6.51 rounds1 tweetstests hypothesis2026-10-05 09:31

    151 commits of pivots

    On 2026-06-11, for ~12 hours, a button in my dashboard turned any page an agent wrote into a public URL. Next morning I swapped it for export: one self-contained html file. By lunch /share was deleted. Export has no URL. A page leaves that button only as a file I chose to send.

    · This is the only candidate and it's close. The numbers and times all trace to the reflog. It's specific, it has the boundary subject H13 needs, and the voice is clean. Don't ship it as written. The closing line is the bo
  22. #098postingstorysinglescore 71 rounds1 tweetstests hypothesis2026-10-04 16:32

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

    My local video generator can take down my desktop. The first run almost did. CPU offload kept ~22 GB of Wan 2.2 weights in host RAM: RAM down to 5% free, swap full, OOM in VAE decode. Now every part loads to the GPU, and a watchdog kills the run if free RAM drops below 6 GB.

    · Every claim traces to project_videolab.md. It is classified as BOUNDARY for H13, with no @mentions and a specific hook. It's OK to post as-is. The optional edits below tighten line 2 and make the line easier to see, with
  23. #097postingstorythreadscore 71 rounds2 tweetstests hypothesis2026-10-04 09:35

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

    My local video generator (Wan 2.2 5B) gets the whole 3090 Ti. My desktop's RAM is off limits. First run used CPU offload: ~22 GB of weights parked in host RAM, 5% of RAM left, swap full, then an OOM in VAE decode. Now a watchdog kills the run if MemAvailable drops below 6 GB.

    Every weight now loads straight to the GPU. The ~11 GB text encoder encodes every prompt, then gets freed before the transformer loads. Running inside that line: a 5-second 1280×704 clip, 40 steps, ~710 s (14.6 s/step).

    · This is the only candidate and it's close to shippable. Every number traces to project_videolab.md or gen.py, and it fits H13 as a boundary post. It needs tightening before it posts. Tweet 1 is about 3 chars under the li
  24. #096rejectedobservationsinglescore 61 rounds1 tweetstests hypothesis2026-10-03 16:31

    151 commits of pivots

    One daemon runs Claude agents for every workspace in mindframe, my agent dashboard. Each agent's $HOME is its workspace, so it loads only its own MCPs, skills and vault. It's an env var, not a sandbox. Every agent runs as my user, so an absolute path reaches other workspaces.

    · This is the only candidate and the claims are accurate and verified, but the hook is buried. The punchline ('it's an env var, not a sandbox') should be the first line. Reorder and tighten it before posting. Once the hook
  25. #095postedcontrariansinglescore 71 rounds1 tweetstests hypothesis2026-10-03 15:46

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

    My 2026 progress page is generated from git. Git doesn't decide what's on it. The build can read any repo in ~/projects. It only counts my 2026 commits, in the 129 projects I listed by hand. It's not on a timer either. A public page shouldn't publish anything I didn't pick.

    x.com/ThatcherThorn/status/2106410505514758629 · The post is accurate, specific and fits H13. It's one tightening pass from shipping. Swap the loose 'can read any repo' for the actual consequence (new repos don't show up), and add the start= detail if space allows.
    ageviewslikesrepliesrepostsbookmarks
    1.64h10000
    3.64h10000
    6.64h10000
    70.65h50000
    72.6h50000
    168.59h50000
  26. #094rejectednumbersinglescore 61 rounds1 tweets2026-10-02 16:44

    151 commits of pivots

    2026-05-17, 5.5 hours, one Claude Code plugin repo: 18:05 UTC: reframe mission: knowledge base + agents, not incident response 19:35: migrate backend from express to fastapi 23:37: convert frontend to vanilla JS, drop Vite Product changed first. Stack followed within hours.

    · This is the only candidate and the facts check out. But the first line is metadata, not a hook, and the post would be an H13 slip because it's about a stack pivot, not a boundary. It's worth posting only after the first
  27. #093postedobservationsinglescore 71 rounds1 tweetstests hypothesis2026-10-02 15:37

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

    My fantasy football agent can propose dropping my defense. It can't make the drop happen. To stream a defense it claims next week's D/ST Wednesday, so I carry two for a day. Claims need my yes. The old one's drop waits: I trigger it after its game. No messaging league mates.

    x.com/ThatcherThorn/status/2106045887818711064 · The claims are accurate and it's on-hypothesis for H13. A short pass to fix the claim/approval contradiction and add one line on why the look-ahead is needed would make it postable.
    ageviewslikesrepliesrepostsbookmarks
    1.73h60000
    3.77h90000
    6.78h120000
    12.73h140000
    24.8h160000
    94.8h300000
    168.77h350000
  28. #092rejectedcontrarianthreadscore 61 rounds3 tweets2026-10-01 16:41

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

    Don't stream a fantasy defense off this week's rankings. By Tuesday or Wednesday, the obvious soft matchup is gone. On traditional waivers with no FAAB budget, a claim filed a week early beats a Sunday scramble. So my waiver bot now looks 3 weeks out.

    For every free D/ST and K, plus mine, per week: - opponent, home/away, bye - how many points the opponent allows to that position, ranked (#32 = most) - @ESPNFantasy's projection The rule: if mine has a bad matchup or bye coming and a free one faces rank 25+, claim it now.

    The cost is a roster spot. Plan: grab next week's defense Wednesday, drop the current one after its game. Two defenses for one day. The claim runs when I reply yes to its text. The drop waits for a separate trigger: the bot can't cut a player who hasn't played yet.

    · This is the only candidate and it's close, but don't post it as-is. Fix the false 'one day' line and the 'can't cut' wording, which turns a deliberate safety rule into a supposed limitation. Tweet 3 can also lean on the
  29. #091failedcontrarianthreadscore 71 rounds3 tweets2026-10-01 09:32

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

    This week's best free defense is the wrong waiver claim. Obvious matchups go Tue/Wed. Claim next week's soft matchup now. Carry both for a day, drop the old one after its game. My fantasy waiver bot now plans it that way: claim, carry, then a drop it isn't allowed to make.

    For every free D/ST and K it reads 3 weeks ahead: opponent, home/away, bye, the opponent's rank vs that position (#32 = softest) and ESPN's projection for each week. @ESPNFantasy's API gives one week of projections per call, so that's one call per week. Fine for 32 rows.

    The drop is the step I don't let it do on its own. It goes in the plan marked after-game, and the runner won't execute it until I trigger that one action by hand. Playbook rule added with it: two defenses for one day, never longer.

    · This is the only candidate and it's close to postable. Every load-bearing claim matches the code. It should also draw replies, because the strongest part is the drop the bot isn't allowed to make, which is the same reach
  30. #090postednumbersinglescore 71 rounds1 tweetstests hypothesis2026-09-30 22:42

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

    I had @claudeai rebuild my income by source from tax PDFs, then diff each year against the filed return. 2020, 2021, 2025: exact match. 2022: off only by Schedule C expenses. 2023, 2024: no return on disk. Only rows off a filed form are verified; the rest are italic.

    x.com/ThatcherThorn/status/2105427981409870045 · This is the only candidate, and it's accurate and specific. It's close to postable. Fix the first line and the last line before posting: lead with the reconciliation result instead of the process, and end on the trust bo
    ageviewslikesrepliesrepostsbookmarks
    1.64h40000
    3.69h40000
    6.71h40000
    12.67h40000
    24.65h50000
    48.71h80000
    135.72h90000
    168.71h90000
    336.69h90000
  31. #089rejectednumbersinglescore 61 rounds1 tweetstests hypothesis2026-09-30 09:34

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

    I had @claudeai rebuild 6 years of household income from old tax docs, then diffed each year against the filed return. 2020, 2021, 2025: exact. 2022: off only by the Schedule C expenses. 2023, 2024: no return on disk, so those years are unverified.

    · This is the only candidate, and it is accurate, clean and the right length. It reads as a status report, not an insight. Add one line on why the only mismatch is Schedule C, or one line on what the unverified years are c
  32. #088postedhowtosinglescore 71 rounds1 tweets2026-09-29 22:43

    CI said green while macOS was failing

    Stock macOS runs your script on bash 3.2. ${s/"$a"/"$b"} keeps the quotes as text. Mine corrupted Obsidian's vault list (invalid JSON) on every Mac that already had one. Fix: r="$b"; ${s/"$a"/$r} CI stayed green anyway: the macOS job was allowed to fail. It now fails the run.

    x.com/ThatcherThorn/status/2105065861375824002 · This is the only candidate, and it holds up. Every load-bearing claim traces to verification.md:71, kb.sh:272-285 and test.yml. The bash 3.2 quote-retention gotcha is specific and useful, and a stranger would learn somet
    ageviewslikesrepliesrepostsbookmarks
    1.63h20000
    3.64h40000
    6.7h50000
    12.65h60000
    24.71h110000
    48.63h110000
    72.69h130000
    168.71h160000
    336.63h160000
  33. #087failedcontrarianthreadscore 71 rounds3 tweets2026-09-29 09:39

    CI said green while macOS was failing

    Marking a new CI platform "allowed to fail" doesn't make it safe to add. It makes it quiet. My plugin's macOS job was allowed to fail, and the run was green. On macOS it was writing invalid JSON into @obsdmd's vault list whenever one already existed.

    Cause: macOS ships bash 3.2. In ${body/"$found"/"..."}, 3.2 keeps the replacement's quotes as literal text, so they land in the JSON. Fix: put the replacement in a variable first, then ${body/"$found"/$rep}. Checked under bash 3.2. The old list is kept beside it as a .bak.

    Second gap: the suites only passed on a machine with Obsidian installed, and on Windows the register tests were skipped without saying so. Now the vault list lives in a test sandbox, so tests don't need Obsidian. All 494 checks pass on macOS.

    · Accurate and specific, and it's close. It needs three edits before posting. Frame the damage as writing into another app's config on the user's machine, close the loop by saying macOS is now a required job, and make the
  34. #086rejectednumbersinglescore 51 rounds1 tweetstests hypothesis2026-09-28 16:42

    151 commits of pivots

    Three commits in 5.5 hours on 2026-05-17 (UTC) rewrote my agent dashboard side project: 1. new mission: a knowledge base agents act on, not an incident-response tool 2. backend: Express → @FastAPI 3. frontend: vanilla JS, Vite dropped Mission, then backend, then frontend.

    · The facts are accurate and specific, but the post doesn't land yet. It has no reason for a stranger to care, the closing line is filler, and the @mention repeats the off-subject tagging the learnings warn against. Fix th
  35. #085rejectednumbersinglescore 61 rounds1 tweetstests hypothesis2026-09-28 09:33

    151 commits of pivots

    In 5.5 hours on one afternoon I changed what my app was for, its backend, and its frontend. mindframe, my agent dashboard, 2026-05-17: 1. Mission: knowledge base + agents, not incident response 2. Backend: Express → @FastAPI 3. Frontend: drop Vite, vanilla JS

    · This is the only candidate. It's accurate and verified, but the ending doesn't pay off. The facts (mission, backend and frontend all changed in 5.5h on 2026-05-17) are real and make a decent number hook. It needs one clo
  36. #084postednumbersinglescore 71 rounds1 tweetstests hypothesis2026-09-27 22:36

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

    My AI-written home page scored 7.14 on a lint for AI-sounding copy. Pages from @basecamp, Stripe, ThoughtWorks, Clearleft, Igalia and Pentagram: 0.35 to 1.33. Score = weighted AI tells per 100 words. Mine had 20 em-dashes, 13 antitheses, "quietly" x3. Fail line: 3.0.

    x.com/ThatcherThorn/status/2104339329254597076 · This is the only candidate and it's close. The numbers are exact and it names the specific failure: 20 em-dashes, 13 antitheses and "quietly" three times. It needs two small edits before posting. Move the fail threshold
    ageviewslikesrepliesrepostsbookmarks
    1.79h30000
    3.74h40000
    6.77h40000
    12.79h40000
    24.78h100000
    48.77h180000
    72.82h210000
    207.82h210000
    336.82h210000
  37. #083postedstorysinglescore 6.51 rounds1 tweetstests hypothesis2026-09-27 15:42

    A cure reserve, priced against three candidate policies

    My 24-month cure reserve (cash that covers a DSCR miss) came out $1 off double the 12-month one. Each was rounded on its own. On a loan screen that reads as wrong math. Fix: round the yearly gap once, then multiply. A @pytestdotorg test pins 24 = 2 × 12 on three inputs.

    x.com/ThatcherThorn/status/2104235346674471173 · This is the only candidate, and it's accurate. It checks out against engine.py:389-395 and test_policy.py:38-43. It's close to postable. It gets a 6.5 because the hook buries the number behind a jargon definition and the
    ageviewslikesrepliesrepostsbookmarks
    3.7h20000
    6.67h30000
    12.69h30000
    24.71h40000
    48.69h60000
    72.66h60000
    214.7h60000
    336.66h60000
  38. #082rejectednumberthreadscore 61 rounds2 tweets2026-09-26 16:30

    A cure reserve, priced against three candidate policies

    A deal misses its 1.25x DSCR floor. Our engine prices the 12-month cure reserve under each candidate policy: In-place NOI (current): $1.17M In-place NOI + 2-yr interest-only: $821k Hybrid (in-place + stabilized) NOI: $51k Hybrid + 2-yr IO: $0 (1.38x), but 1.23x once amortizing

    Same $25.6M loan, priced instead of rejected. The NOI basis moves the cure over 20x; interest-only barely moves it.

    · The numbers are real and specific, and I re-derived every figure. But the takeaway line misstates what IO does, the hybrid+IO '$0' overstates the result, and the post breaks the open H12 single-mention rule. It needs one
  39. #081rejectednumbersinglescore 61 rounds1 tweets2026-09-26 09:31

    A cure reserve, priced against three candidate policies

    A loan needed 1.25x debt-service coverage (DSCR). It had 0.79x. The room guessed interest-only (IO) cuts payments 30-40%. It cuts ~11%: 0.79x → 0.89x. Still fails. The lever is NOI basis. Stabilized rent at current occupancy: 1.23x. Add IO: 1.38x (passes), 1.23x amortizing.

    · Only one candidate, and it's close. The numbers are verified and the hook is concrete, but the ending is muddled and it goes over the character budget. With the ending fixed it's postable.
  40. #080rejectednumbersinglescore 61 rounds1 tweetstests hypothesis2026-09-25 16:38

    A cure reserve, priced against three candidate policies

    The @claudeai deal chat put a DSCR-miss cure at ~$890k. The engine says $1.17M/yr. The room had put NOI at "2.2 or whatever it is" ($M). The file says $2.01M. The chat likely took the room's. Now the engine does that arithmetic and the decline panel prints it; the chat doesn't.

    · This is the only candidate, and it's worth revising rather than replacing. It has a real number hook, the numbers are verified, and the @mention is legitimate for H11 test 4, which must ship as MENTION. It shouldn't go o
  41. #079postednumbersinglescore 71 rounds1 tweetstests hypothesis2026-09-25 15:42

    chess-trainer went phone-first in one commit

    An unwrapped markdown table made my chess app 506px wide on a 390px phone. Fix: wrap it in .tablewrap. Other desktop defaults that broke: sub-16px inputs made iOS zoom on focus, icon buttons too small to tap (now 44px), and move-list scrollIntoView dragged the board off screen.

    x.com/ThatcherThorn/status/2103510336431370639 · I'd post this. Every number traces to the chess-trainer CLAUDE.md (:33–:37), the hook is specific, and the list of failures is real and useful to anyone who builds for phones. It's a NONE arm for H11, so it can only go i
    ageviewslikesrepliesrepostsbookmarks
    1.66h90000
    3.69h90000
    6.7h90000
    12.72h110000
    24.71h140000
    48.71h151000
    72.73h171000
    168.71h171000
    336.69h171000
  42. #078postednumbersinglescore 7.51 rounds1 tweetstests hypothesis2026-09-24 22:36

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

    Two repos. That's all my contract-signing app can touch on GitHub. Org policy disables deploy keys, so plan A died. Plan B: a GitHub App via the manifest flow, installed on contracts + legal-documents only. Widening it means the org settings page. My own gh token gets a 403.

    x.com/ThatcherThorn/status/2103252184993538314 · Post it. Every claim checks out, it fits the H11 NONE slot, and it follows the one pattern that has drawn replies: naming a scope boundary on my own infra. The edit below is optional. Do it only if it keeps the post with
    ageviewslikesrepliesrepostsbookmarks
    1.74h80000
    3.8h110000
    6.75h110000
    12.79h110000
    24.75h140000
    48.81h150000
    72.79h160000
    168.75h170000
    336.79h170000
  43. #077postednumbersinglescore 71 rounds1 tweetstests hypothesis2026-09-24 15:45

    The heat map's first hotspot was null island

    80% of pings in a dataset sat on one coordinate at accuracy 0. Not a crowd. A vendor's IP-geolocation city point, not a place anyone stood. geolab (on @duckdb) now drops any exact coordinate shared by 10+ devices from presence counts. Devices of interest: 10,089 → 1,966.

    x.com/ThatcherThorn/status/2103148706883322140 · This is close. Every number checks out and the hook is the strongest type this account has. It doesn't pass as-is because the payoff line depends on the undefined term 'devices of interest', and the @duckdb tag is only l
    ageviewslikesrepliesrepostsbookmarks
    1.64h20000
    3.64h20000
    6.65h80000
    12.63h140000
    24.61h180000
    48.66h190000
    72.66h190000
    168.62h210000
    336.66h210000
  44. #076postedcontrariansinglescore 71 rounds1 tweetstests hypothesis2026-09-23 22:41

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

    You don't need a flight price API to watch one route. Google Flights puts the cheapest fare in the raw HTML: "From 613 US dollars round trip total." My watcher: one plain GET every 3 hours, one regex. No JS, no key. Economy is Basic + $120. Slightly off beats silently broken.

    x.com/ThatcherThorn/status/2102891021315248498 · This is the only candidate and it's close. Every number traces to config.json, source.py or history.jsonl. The quoted HTML string is a specific, checkable hook, and a contrarian framing is what H10 needs in the next slot
    ageviewslikesrepliesrepostsbookmarks
    1.73h70000
    3.69h100000
    6.69h130000
    12.71h130000
    24.74h160000
    48.67h190000
    72.72h220000
    168.74h300000
    336.72h300000
  45. #075postedstorysinglescore 71 rounds1 tweetstests hypothesis2026-09-23 15:34

    Four drill types, one source: your own lost games

    My AI chess coach read ~1,030 of my games and was right about what I was doing wrong. I still had nothing to do about it on a board. A second agent turns them into drills: middlegames where I was up 2.5 pawns and threw it away, replayed until I beat Stockfish set to 2000.

    x.com/ThatcherThorn/status/2102783740040888825 · Candidate 0 is the only draft and a good one. It meets H10's STORY requirement without being a failure-and-fix story, every number traces to code or memory, and the voice is clean. Two wording fixes are needed before pos
    ageviewslikesrepliesrepostsbookmarks
    1.84h40000
    3.8h40000
    6.78h50000
    12.78h80000
    24.79h100000
    48.78h120000
    72.83h130000
    168.8h130000
    336.79h130000
  46. #074postednumbersinglescore 81 rounds1 tweetstests hypothesis2026-09-22 22:38

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

    Counting who was inside a geofence over 1M visits: >300 s and 7.9 GB as a Python loop. ~2 s and 277 MB as DuckDB SQL. 20M synthetic pings, 2,000 devices. The loop was also wrong: 69 visitor origins at one fence. SQL found 81, matching a brute-force min(ts) subquery.

    x.com/ThatcherThorn/status/2102527861894865085 · This is good enough to post as-is. All the numbers are verified, it opens with a concrete before/after, and it closes by showing the old loop was wrong as well as slow, which gives it more substance than a plain benchmar
    ageviewslikesrepliesrepostsbookmarks
    1.77h50000
    3.74h80000
    6.72h150000
    12.74h200000
    24.73h250000
    48.79h310000
    72.72h320000
    168.73h340000
    336.79h340000
  47. #073postedstorysinglescore 81 rounds1 tweetstests hypothesis2026-09-22 15:51

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

    12:26, I committed a terminal pane into geolab, my map app. 12:28, I committed the fix. pty.fork() hands the child every open fd, so tmux inherited uvicorn's listening socket and kept the port bound. os.closerange(3, 65536) before execvpe. The bug was two minutes old.

    x.com/ThatcherThorn/status/2102425481744384166 · Strong post, one edit short of shipping. The only candidate is also a genuinely good one: verified to the second against .git/logs/HEAD and to the line against server.py:2811-2815, correctly scoped away from the one clai
    ageviewslikesrepliesrepostsbookmarks
    1.52h30000
    3.5h30000
    6.52h50000
    12.52h100000
    24.54h120000
    48.52h150000
    72.51h170000
    168.56h170000
    336.52h170000
  48. #072postednumbersinglescore 7.51 rounds1 tweetstests hypothesis2026-09-21 22:43

    taskpilot's first non-Claude-Code provider

    Spawning an autonomous agent on Claude Code: tmux new-session, sleep 7, send Enter, sleep 4, send Enter. To read what it did, attach to the pane. Same daemon API on opencode: one POST /api/session, an HTTP transcript, and a crash resumes the same session with its history.

    x.com/ThatcherThorn/status/2102166769947582610 · Best and only candidate; close to shippable but not as-is. The engineering is verified down to line numbers and the voice is right — flat, no hype, no emoji, a stranger gets the joke about sleep 7 / send Enter. What it g
    ageviewslikesrepliesrepostsbookmarks
    1.65h120000
    3.65h140000
    6.69h170000
    12.67h200000
    24.64h210000
    48.64h250000
    72.7h270000
    168.67h270000
    351.7h270000
  49. #071postedstorysinglescore 7.51 rounds1 tweetstests hypothesis2026-09-21 15:45

    Shards become subagents: exposing long-lived sessions over MCP

    I'd been treating in_flight in conduit's registry as a lock on a worker session. It isn't. reconcile() clears it on load, and it races — so two resumes can interleave turns into one transcript. Fix: an O_EXCL lockfile per shard, stale at 900s, one reclaim, live holder wins.

    x.com/ThatcherThorn/status/2102061642985226612 · Only candidate, and it is genuinely close - accurate throughout, correctly failure-led for H9's next slot, and built on the one hook (story) holding above the post-drop floor of 10. Not post-as-is for two fixable reasons
    ageviewslikesrepliesrepostsbookmarks
    1.63h20000
    3.67h20000
    6.67h40000
    12.6h60000
    24.64h90000
    48.63h130000
    72.61h130000
    168.67h160000
    358.66h160000
  50. #070postednumbersinglescore 6.51 rounds1 tweetstests hypothesis2026-09-20 22:41

    [CONFIRM] markers instead of guesses

    Two brackets in my LLC's signable documents are still open. They say [CPA], not [CONFIRM]. The AI draft never guessed at a blank. Venue, tax distribution %, the $25k contract threshold, late-payment interest — I closed those myself, no lawyer, in a file that prices being wrong.

    x.com/ThatcherThorn/status/2101803908171739197 · Only candidate, and it is genuinely postable — accurate, in-protocol, correctly the FINDING-led arm H9 requires after id69. But not as-is: it buries its own lede. Invert the two halves so the first line is 'an AI drafted
    ageviewslikesrepliesrepostsbookmarks
    1.69h30000
    3.69h40000
    6.66h40000
    12.73h80100
    24.67h140100
    48.67h200100
    72.67h220100
    168.7h220100
    375.73h220100
    @gethandledapp Those brackets are the honest part. A blank that says [CPA] is better than an AI filling it with a guess you never chose. The venue and the interest rate you decided yourself, and that is the part that holds.
  51. #069postedstorysinglescore 7.51 rounds1 tweetstests hypothesis2026-09-20 15:50

    128K context cost 23 tokens/sec

    My Qwen3.6 35B was capped at 32K. The GGUF metadata says 262K - the cap was mine, set once and never revisited. Fix: 131072 ctx + q8_0 KV cache. The abliterated build lands at 22.8GB of 24. Price: 152 tok/s to 129. 4x context, 15% slower. I left gpt-oss-20b at 32K.

    x.com/ThatcherThorn/status/2101700450030608734 · Only candidate, and it is genuinely close -- accurate, dense, correct hook type, correct H9 arm. Holding it back for one pass because two cheap edits move it: the 262K ceiling should lead (it is the surprise; 32K alone i
    ageviewslikesrepliesrepostsbookmarks
    1.57h10000
    3.55h60000
    6.52h70000
    12.55h140000
    24.53h190000
    48.56h530000
    72.55h630000
    168.57h650000
    382.58h650000
  52. #068postednumbersinglescore 7.51 rounds1 tweetstests hypothesis2026-09-19 22:50

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

    Sponsor's model: DSCR 1.58x. Mine: 0.79x. Same property, same ask. The difference is which NOI. Theirs is Year-3 stabilized. Mine is the in-place rent roll. Below the 1.25x floor the engine declines — and prints what in-place NOI does support: ~$16.5M against a ~$26M ask.

    x.com/ThatcherThorn/status/2101443952717226017 · Only one candidate, and it's close to postable — accurate, specific, correctly sized, no hype. Don't post as-is: fix the authorship gap first. Right now nothing in the post says the 0.79x came from software you wrote, so
    ageviewslikesrepliesrepostsbookmarks
    13.51h50000
    24.53h90000
    48.51h110000
    72.51h110000
    168.56h110000
    399.56h110000
  53. #067postedstorysinglescore 71 rounds1 tweetstests hypothesis2026-09-19 15:39

    62 companies, 4 sector agents, one merge script

    Slug-only dedupe would have shipped Unilever twice. 4 agents, 65 labor-abuse entries, 62 companies. Amazon and Temu shared a slug. Easy. Unilever didn't: "unilever" vs "unilever-ben-jerrys". Only the shared domain caught it. Match on domain too, or agent overlap becomes dupes.

    x.com/ThatcherThorn/status/2101335481103634441 · This is the only candidate and it's accurate. The numbers and the Unilever slug/domain example match the source files. It's close, but lines 2–4 don't tell a stranger why the dedupe matters, and the last line reads awkwa
    ageviewslikesrepliesrepostsbookmarks
    1.71h40000
    3.72h60000
    6.74h90000
    12.72h90000
    24.71h120000
    48.7h130000
    72.73h190000
    168.74h260000
    336.76h260000
  54. #066postedobservationsinglescore 7.51 rounds1 tweetstests hypothesis2026-09-18 22:37

    Lose the key, lose the history

    Same app, same server, two URLs: two different people. My E2E chat keeps each device's key in localStorage, which is per origin. Open it from the backup URL and you're a stranger with no history. No key escrow, so nobody can merge them back. The README now says: pick one URL.

    x.com/ThatcherThorn/status/2101078288433319992 · Postable as written. Every claim checks out against the backchannel README (lines 4-9 and 35). It's a single post at about 279 characters about my own infrastructure, so it fits the fixed copy rules for H8. The origin-sp
    ageviewslikesrepliesrepostsbookmarks
    2.77h20000
    3.77h30000
    6.73h40000
    12.77h50000
    24.75h100000
    48.74h110000
    72.72h110000
    168.72h110000
    336.77h110000
  55. #065postednumbersinglescore 7.51 rounds1 tweetstests hypothesis2026-09-18 15:41

    One flag: 90 tok/s to 282

    One llama.cpp flag tripled prompt processing on my 3090 Ti box. Qwen3-Coder-Next 80B-A3B, ~16GB of it spilled into system RAM. -ub 512 (default): 90 tok/s prefill -ub 2048: 282 tok/s For a CPU-offloaded MoE, ubatch size is the lever. Generation: ~50 tok/s.

    x.com/ThatcherThorn/status/2100973466136854799 · This one can ship. Every number checks out against the evidence file. It avoids the idea's unverified claim that generation 'barely moved', and it fits H8's fixed-copy constraints (single tweet, 250–280 characters, my ow
    ageviewslikesrepliesrepostsbookmarks
    1.68h50000
    3.67h90000
    6.69h140000
    12.72h190000
    24.66h220000
    48.69h250000
    72.67h250000
    168.67h280000
    336.72h280000
  56. #064postedstorysinglescore 71 rounds1 tweetstests hypothesis2026-09-17 22:38

    Rank cliff vs. marginal-starter threshold

    My startable filter found exactly 10 startable QBs in a 10-team league. It was a rank cutoff. It was counting itself.

    x.com/ThatcherThorn/status/2100716072395841683 · Only candidate, and it is close to shippable: the claim is verifiable in build.py, the length and hook type are exactly what H7 calls for on 09-18 09:00, and the voice is clean. Two small things keep it from post-as-is —
    ageviewslikesrepliesrepostsbookmarks
    2.71h21000
    3.75h61000
    6.71h61000
    12.75h71000
    24.73h111000
    48.73h121000
    72.73h131000
    168.78h131000
    336.71h131000
  57. #063postedstorysinglescore 71 rounds1 tweetstests hypothesis2026-09-17 15:40

    Two ways a new domain breaks your Cloudflare + Resend stack

    I ran cloudflared tunnel route dns for a new domain. No error. It created the record as a subdomain of my other domain, wildcard included. It writes to whatever zone cert.pem is bound to, not the hostname you pass. Any other domain: add the CNAME by hand in its own zone.

    x.com/ThatcherThorn/status/2100610752898097307 · This is the only candidate and it's close. It's accurate, specific, and failure-plus-fix, and it fits the 09-17 09:00 H7 long slot. Two unclear phrases ('my other domain', 'Any other domain') make a stranger stop to work
    ageviewslikesrepliesrepostsbookmarks
    1.73h110100
    3.7h130100
    6.71h160100
    12.69h210100
    24.76h240100
    48.68h410100
    72.71h540100
    168.7h900100
    336.71h1010100
    @JayQinQT That usually means cloudflared is using the account/zone tied to cert.pem, not the hostname's zone. Check the active cert/account, then create the CNAME in the target zone or use named-tunnel credentials from that zone. For a quick localhos
  58. #062postedcontrariansinglescore 6.51 rounds1 tweetstests hypothesis2026-09-16 22:36

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

    19 commits in 4 hours, a week after a lending workshop. I'd credited four of them to the workshop. The findings doc backs one: stage labels switched to the lenders' own gate names. The other three: server hardening, plus a daily digest moved to a timer and deleted 28 min later.

    x.com/ThatcherThorn/status/2100353109197517039 · This is the only candidate, and it's close. Every load-bearing number traces to the reflog and the workshop doc. Two fixes before 09-17 09:00. First, say the 19 commits 'landed', because 6 of them arrived as a 3-minute b
    ageviewslikesrepliesrepostsbookmarks
    1.82h20000
    3.8h40000
    6.75h40000
    12.73h40000
    24.77h70000
    48.77h100000
    72.77h110000
    168.75h110000
    336.82h110000
  59. #061postedobservationsinglescore 71 rounds1 tweetstests hypothesis2026-09-16 15:39

    Reload survives. Restart doesn't.

    Reload my chat app: every conversation comes back. Restart its server: all gone. History lives in RAM, on purpose.

    x.com/ThatcherThorn/status/2100248250024599560 · This is the only candidate, and it's accurate, clean and within H7's ≤120-char limit. It works as a short-side H7 test as written. The one real problem is the closing line: 'History lives in RAM' doesn't say which side h
    ageviewslikesrepliesrepostsbookmarks
    2.72h10000
    3.75h10000
    6.73h20000
    12.71h40000
    24.75h70000
    48.77h80000
    72.69h80000
    168.72h80000
    336.71h80000
  60. #060postedstorysinglescore 7.51 rounds1 tweetstests hypothesis2026-09-15 22:44

    DNS must always have a fallback

    One reboot took DNS down on every device on my tailnet. Tailscale came back stopped, so 100.99.44.89 was gone. Pi-hole binds that IP on :53, so it died. It was the tailnet's only nameserver. Now tailnet DNS is Pi-hole, then 1.1.1.1. Blocking can fail; resolving can't.

    x.com/ThatcherThorn/status/2099992792701534228 · This is the only candidate, and it's accurate, specific and on-format for H6's required unnamed slot. Two small edits would make it clearer and add the detail readers won't expect. Ship it after those edits, tagged H6, a
    ageviewslikesrepliesrepostsbookmarks
    1.67h110100
    3.65h110100
    6.61h130100
    12.65h160100
    24.66h190100
    48.64h220100
    72.63h230100
    168.62h280200
    336.62h280200
    @Vorithio Pi-hole as the only nameserver on your tailnet still asks whose box that reboot just took down.
  61. #059postedcontrariansinglescore 71 rounds1 tweets2026-09-15 15:46

    Contaminated data gives confident wrong answers

    0.0° error across 21 holes is not a result. It's a sign you have 1 hole. My Wii Sports Resort golf data had 21 "per-hole" files, all byte-identical. Every check fit that one file 21 times. Before handing a dataset to Claude: md5sum * | sort -u | wc -l. 21 files should print 21.

    x.com/ThatcherThorn/status/2099887608340095199 · This is the only candidate and it's close. The hook and the md5sum takeaway are good. Don't post it as-is, for two reasons: two phrases say more than the evidence supports ('0.0° error', 'Every check fit'), and it goes o
    ageviewslikesrepliesrepostsbookmarks
    1.61h20000
    3.59h50000
    6.58h70000
    12.56h90000
    24.62h130000
    48.63h170000
    72.65h200000
    168.62h220000
    336.63h230000
  62. #058postednumbersinglescore 6.51 rounds1 tweetstests hypothesis2026-09-14 22:45

    Five hypotheses my agent swarm inverted

    Haiku 4.5 is the only Claude model that writes readable thinking to my local transcripts. So I checked whether it's telegraphic. Function words per 100 words: thinking 42.02, prose 42.07. Only real gap: ~2x more verbless lines. It isn't compressed. It's outline-shaped.

    x.com/ThatcherThorn/status/2099630636592197657 · This is the only candidate. Every number traces to exp-cot-compression/RESULTS.md, and the post qualifies as an H6 'named' single. It isn't ready yet: the opening line skips the belief being overturned, and the post neve
    ageviewslikesrepliesrepostsbookmarks
    1.6h30000
    3.61h30000
    6.59h40000
    12.63h60000
    24.6h80000
    48.65h100000
    72.62h110000
    168.6h110000
    336.63h110000
  63. #057postedcontrariansinglescore 71 rounds1 tweetstests hypothesis2026-09-14 15:47

    Lines of code lie

    My git history says I added 6.18M lines since Nov 2025. The real number is 754k. One "initial commit" in my claude-security repo added 5,067,963 lines. A vendored dump in email-triage: 355k. Those two repos later deleted 5.42M. Net from both: about +4k. Quote the 754k.

    x.com/ThatcherThorn/status/2099525403438366838 · This is the only candidate. It's close to postable: the numbers are specific, consistent and cited, and the opener is strong. Fix the closer and the 'real number' overclaim before posting. Also make a deliberate call on
    ageviewslikesrepliesrepostsbookmarks
    1.63h60000
    3.6h70000
    6.58h70000
    12.6h70000
    24.61h70000
    48.61h80000
    72.62h80000
    168.57h100000
    336.63h100000
  64. #056rejectedstorysinglescore 61 rounds1 tweetstests hypothesis2026-09-13 16:31

    Lines of code lie

    One commit in my claude-security repo added 5,067,963 lines: "initial commit." Git census of 150 repos: 6.18M lines added. Drop that repo and email-triage (355k): 754k. Both vendored dumps were later deleted, so net they added almost nothing. Still 88% of lines added.

    · This is the only candidate and it can be saved. The first line and the numbers are good and check out. The ending is muddled: the 88% has no clear subject, the 'net nothing' point comes in too late, and the lesson is nev
  65. #055rejectednumbersinglescore 21 rounds1 tweetstests hypothesis2026-09-13 09:42

    Lines of code lie

    My git history says I added 6.2M lines. 5.07M of them are one "initial commit" in [REPO]: vendored [LIBRARY]. Remove that and one more vendored dump and it's 754k. Raw is about 8x the cleaned number. Sort commits by insertions before you sum anything.

    · This is the only candidate, but it's unfinished and unverified: two placeholders are still in, and none of the three main numbers can be traced to a file. I found no gitstats*.json. Rewording won't save it. Rerun `git lo
  66. #054rejectednumbersinglescore 31 rounds1 tweetstests hypothesis2026-09-12 16:35

    Lines of code lie

    My lifetime lines added across every repo: 6.2M. Drop two commits and it's 754k. Both were "initial commit" dumps of vendored code I didn't write. One was 5.07M lines by itself. Sort git log --numstat by insertions and read the top few before quoting any LOC number.

    · Don't post this. There's only one candidate and it hard-fails on accuracy: gitstats.json isn't on disk, and 6.2M / 754k / 5.07M come only from the idea's own text in ideas.json. The subtraction also leaves about 376k lin
  67. #053postedcontrariansinglescore 81 rounds1 tweetstests hypothesis2026-09-12 15:42

    Top 15 repos, colored by Claude share

    Every commit in cool-af and taskpilot has one author: me. git shortlog reads 100% human. Both were built with Claude. Claude's share lives nowhere in the author field. It's a trailer in the commit body: Co-Authored-By: Claude Fable 5. An "AI wrote X%" chart is about trailers.

    x.com/ThatcherThorn/status/2098799441474199827 · Only candidate, and it is close to postable. It does the hardest thing right: the idea's named evidence (gitstats.json, the 82/83/90% chart) does not exist on disk, and instead of inventing the chart it pivots to a claim
    ageviewslikesrepliesrepostsbookmarks
    1.69h781100
    3.63h951100
    6.67h991100
    12.65h1021100
    24.7h1051100
    48.67h1071100
    72.69h1091100
    168.64h1091100
    336.7h1091100
    @cloneisjun git saying human while claude wrote it all
  68. #052rejectedobservationsinglescore 61 rounds1 tweetstests hypothesis2026-09-11 16:38

    Top 15 repos, colored by Claude share

    Claude wrote most of taskpilot and cool-af. Almost none of my notes vault. The split isn't language or size. It's whether an agent is part of the runtime: taskpilot spawns a Claude session per task, cool-af one per pasted URL. The vault is hand-typed, and nothing runs it.

    · Only candidate, and it is salvageable but not postable. The draft is honest and well-verified — I confirmed both mechanisms in the repos and the char count, and the writer was right to delete the mindframe claim and righ
  69. #051postedobservationsinglescore 71 rounds1 tweets2026-09-11 15:41

    When I actually code

    Every git commit has two timestamps, and only one survives a rebase. %cd, committer date: rebase, amend and cherry-pick reset it to when you ran them. %ad, author date: kept through all three. So if you chart when you work from git, chart %ad. %cd shows your last rebase.

    x.com/ThatcherThorn/status/2098436767473193082 · This is the only candidate, and after one edit it can be posted. Dropping the heatmap and switching to the %ad/%cd point was the right move, because the data file is gone. The git claims are accurate and the post fits th
    ageviewslikesrepliesrepostsbookmarks
    1.73h50000
    3.68h50000
    6.69h50000
    12.68h70000
    24.7h100000
    48.71h120000
    72.69h120000
    168.73h130000
    336.67h130000
  70. #050rejectedhowtosinglescore 31 rounds1 tweetstests hypothesis2026-09-10 16:43

    When I actually code

    Your real working hours are already in git: git log --author=YOURNAME --date=format:'%a %H' --format=%ad | sort | uniq -c | sort -rn Summed across my repos, Wednesday is the quietest weekday: [W] commits vs Monday's [M]. I still don't know why.

    · This is the only candidate and it doesn't clear the bar. Its structure is fine, but the two numbers are placeholders and the Wednesday claim can't be checked against current data, because gitstats.json no longer exists a
  71. #049rejectedcontrariansinglescore 51 rounds1 tweets2026-09-10 09:31

    When I actually code

    My agents can run overnight. The commit log says almost nothing does. Nine months by hour: under a tenth of my commits land at night. Peaks mid-morning and just after lunch, and Wednesday is the emptiest weekday, under half of Monday. Autonomy moved the typing, not my hours.

    · Only one candidate, and it is close but not postable as-is. The hook and voice are the strongest part and should survive untouched; the failure is that the source data (gitstats.json) no longer exists, so the draft eithe
  72. #048postedobservationsinglescore 71 rounds1 tweetstests hypothesis2026-09-09 22:50

    The Big Bang: 92 repos in 26 days

    Three repos with nothing in common got their first commit inside 16 seconds on March 23. agentwatch at 15:19:37. gmail-mcp at 15:19:51. hardcore-hiscore at 15:19:53. Three parent directories, not a monorepo split. Three git inits, one afternoon where starting cost nothing.

    x.com/ThatcherThorn/status/2097819957908378062 · Only candidate, and it is close to postable: accurate to the second, concrete, in-band, no hype or hashtags. Two cheap fixes stand between it and 'post as-is'. First, the hook delays its own surprise — '16 seconds' shoul
    ageviewslikesrepliesrepostsbookmarks
    1.52h70000
    3.55h70000
    6.58h70000
    12.58h70000
    24.52h80000
    48.57h91000
    72.53h121000
    168.56h121000
    336.52h121000
  73. #047postednumbersinglescore 7.51 rounds1 tweetstests hypothesis2026-09-09 15:50

    The day I shipped 200 commits across 48 repos

    Five repos got their first commit on the same day: 09:50, 13:23, 13:28, 13:42, 15:21. Five months later two are in archive/. One of those has three commits in its whole history: born, favicon swap, delete the CI workflows — and the last two were fleet sweeps, not work.

    x.com/ThatcherThorn/status/2097714193726316618 · Only one candidate, and it is genuinely solid -- fully verified, concrete, correctly formed for the house recipe and usable as an H4 pair member. It is not accept-as-is because the best fact in it is in the wrong positio
    ageviewslikesrepliesrepostsbookmarks
    3.58h10000
    6.55h50000
    12.55h60000
    24.53h60000
    48.55h70000
    72.55h70000
    168.56h80000
    336.55h80000
  74. #046postednumbersinglescore 71 rounds1 tweetstests hypothesis2026-09-08 22:55

    One-commit ideas

    orecast has one commit: "scaffold orecast prospecting pipeline." 9 CLI commands, 5 source configs, a scorer that ranks ideas on buildability and competition gap. The db it writes to is still in ~/.orecast, so it ran at least once. That was March 26. Commit 2 never came.

    x.com/ThatcherThorn/status/2097458745295167601 · Only candidate, and it is close to shippable: the facts are all verifiable in projects/softwaresoftware/projects/archive/orecast and the voice is right. Do not post as-is. It burns a third of its budget on the vaguest tr
    ageviewslikesrepliesrepostsbookmarks
    1.48h10000
    3.44h40000
    6.45h50000
    12.47h50000
    24.44h50000
    48.44h50000
    72.49h60000
    168.44h70000
    336.44h70000
  75. #045postednumbersinglescore 7.51 rounds1 tweetstests hypothesis2026-09-08 15:50

    Four notification plugins, one capability

    4 plugins, 1 tool signature: send_notification(message). notify-linux shells out to notify-send. notify-windows builds toast XML. notify-slack POSTs a webhook. notify-email opens SMTP on 587. One capability, picked by an install-time probe. No shared code, no base class.

    x.com/ThatcherThorn/status/2097351814484197402 · Only candidate, and it is genuinely postable — every number traces to the repo, it is on-recipe (single, 273 chars), and it is a valid number-led H3 test, which is the side the alternation is currently short on. Not acce
    ageviewslikesrepliesrepostsbookmarks
    1.57h40000
    3.59h50000
    6.52h70000
    12.55h100000
    24.56h130000
    48.53h140000
    72.55h150000
    168.56h160000
    336.55h160000
  76. #044postedobservationsinglescore 71 rounds1 tweets2026-09-07 22:38

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

    My installer test suite was green the whole time it was firing real telemetry. 92/92 passing, with the tests posting to telemetry.softwaresoftware.dev. Telemetry also defaulted to on for customers. The suite was exercising the thing I should have been gating.

    x.com/ThatcherThorn/status/2097092270478831941 · Only one candidate, and it is close but not post-as-is. The core observation is real, verified, and the right kind of specific — a green suite that was green because it was doing the bad thing. It fails the stranger test
    ageviewslikesrepliesrepostsbookmarks
    3.77h20000
    6.77h20000
    12.72h20000
    24.76h40000
    48.71h60000
    72.71h70000
    168.71h80000
    336.7h80000
  77. #043postednumbersinglescore 71 rounds1 tweetstests hypothesis2026-09-07 15:40

    Claude Code walks up from cwd to $HOME

    1 directory level separated my isolated agents from my personal ~/.claude. Claude Code walks up from cwd for skills, rules and CLAUDE.md, stopping at $HOME. The sandbox $HOME sat one level below cwd, so it walked past into my real one. Fix: task dir = home dir, so HOME == cwd.

    x.com/ThatcherThorn/status/2096986871494828109 · Only one candidate, and it is genuinely postable — accurate, in-form, correctly number-led for H3, and the underlying gotcha (Claude Code discovers .claude config by walking up from cwd and only stops at $HOME) is real,
    ageviewslikesrepliesrepostsbookmarks
    1.72h130000
    3.72h190000
    6.67h260000
    12.71h450000
    24.75h560000
    48.72h610000
    72.7h680000
    168.71h720000
    336.69h720000
  78. #042postedstorysinglescore 71 rounds1 tweetstests hypothesis2026-09-06 22:47

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

    taskpilot 0.9.0 gave spawned agents a sandboxed $HOME. Context floor: ~47k to ~33k tokens. 0.12.0 deleted it 20 days later. Agents inherit the real ~/.claude again: every plugin, every MCP server, the rules. enabled_plugins and enabled_mcps went with it. Sandbox-only code.

    x.com/ThatcherThorn/status/2096731936232521752 · Only candidate, and it is close — factually clean, right form for the open hypothesis, right length band. Not postable as-is: the reversal that makes the story worth reading is stranded in line 2, and the closer compress
    ageviewslikesrepliesrepostsbookmarks
    1.64h220100
    3.64h280100
    6.59h300100
    12.56h340100
    24.62h410100
    48.63h420100
    72.57h530100
    168.57h570100
    336.59h570100
    @TerminusProto The config inheritance is the sharp edge here—sandboxing code while carrying over the real plugin/MCP state makes runs hard to reproduce. A run-level manifest for enabled_plugins and enabled_mcps would make that boundary auditable.
  79. #041postedcontrariansinglescore 71 rounds1 tweetstests hypothesis2026-09-06 15:41

    A frame is a directory, not a registration

    There is no register_frame() in my agent dashboard. An agent publishes by making a directory. Any dir under ~/.mindframe/frames/ with an index.html is live: listed in the dock, served at /m/<id>, messages routed to the task in its meta.json. Delivery is mkdir plus two files.

    x.com/ThatcherThorn/status/2096624830544318845 · Only candidate, and it is postable and accurate — but not as-is. It is a correct H2 single (non-number opener, 277 chars, standalone) with every fact verified in both the doc and server.py. What it wastes is its third be
    ageviewslikesrepliesrepostsbookmarks
    1.67h40000
    3.66h40000
    6.7h40000
    12.67h70000
    24.67h70000
    48.72h70000
    72.7h70000
    168.71h80000
    336.68h80000
  80. #040postedcontrariansinglescore 7.51 rounds1 tweetstests hypothesis2026-09-05 22:56

    Chat, Cowork, Code: three products wearing one app

    Cowork "does not receive server-managed settings by design." Anthropic's model-config docs. So an MDM availableModels file governs Code and local Cowork, not remote. Chat, Cowork, Code are not tiers. They're three governance planes wearing one icon. https://research.softwaresoftware.dev/posts/claude-desktop-chat-vs-cowork-vs-code/

    x.com/ThatcherThorn/status/2096371930974818549 · Only candidate, and it is genuinely close - accurate, well-sourced, correctly sized, and it lands in the single slot H2 needs on 2026-09-06. Not accept-as-is for one fixable reason: line 3 sells a three-plane conclusion
    ageviewslikesrepliesrepostsbookmarks
    1.41h100000
    3.43h140000
    6.48h170000
    12.48h190000
    24.48h330000
    48.46h360000
    72.47h370000
    168.43h400000
    336.43h400000
  81. #039rejectedobservationthreadscore 61 rounds4 tweetstests hypothesis2026-09-05 09:34

    Chat, Cowork, Code: three products wearing one app

    Server-managed settings from Anthropic's admin console reach Claude Code and, by design, not Cowork. Three tabs in one app, no shared permission model, settings path, memory store, or audit trail. All 33 cells checked against Anthropic's docs — not a light-medium-heavy ladder.

    A managed-settings file only applies where the session physically runs — and remote Cowork runs on Anthropic VMs. Anthropic's wording: "not a Claude Code surface... does not receive server-managed settings by design." So availableModels won't keep Cowork off an expensive tier.

    Two more seams: Cowork doesn't read the CLI's ~/.claude, so a skill your devs live in is invisible there. And Chat memory doesn't carry into Cowork — only project memory, only inside that project. Full 11x3 matrix, every cell verified 2026-08-06: https://research.softwaresoftware.dev/posts/claude-desktop-chat-vs-cowork-vs-code/

    verified

    · Only one candidate, and it is genuinely good research writing that is one stray array element away from being unpostable. The claims survive line-by-line verification against the source post, the hook names a concrete go
  82. #038failedcontrarianthreadscore 81 rounds3 tweetstests hypothesis2026-09-04 16:30

    Chat, Cowork, Code: three products wearing one app

    Same product name, opposite defaults. "Run Cowork in the cloud" is on by default on Team and off by default on Enterprise. Three tabs in one Claude Desktop window, and they share no permission model, no settings-delivery path, no memory store, and no audit pipeline.

    2/ Cowork is not Claude Code with training wheels. Same agentic architecture, separate governance plane. Anthropic's wording: it "is not a Claude Code surface and does not receive server-managed settings by design." Your MDM availableModels policy does not reach it.

    3/ Four seams, all documented, all able to eat a day: Cowork doesn't read ~/.claude. Admin-console policy doesn't reach Cowork. Chat memory doesn't carry into Cowork. Desktop plugins don't reach cloud Code sessions. 33 cells, verified 2026-08-06: https://research.softwaresoftware.dev/posts/claude-desktop-chat-vs-cowork-vs-code/

    · Only candidate, and it is genuinely good - the strongest-evidenced draft this account has queued, and the correct form for the next H2 slot. Not quite post-as-is. Two fixes are worth making: tweet 1 says 'three tabs' but
  83. #037postedcontrarianthreadscore 81 rounds3 tweetstests hypothesis2026-09-04 15:47

    42.02 vs 42.07

    Everyone says agent chain-of-thought reads like a telegram because RL squeezes it. I scanned 4,343 Claude transcripts and paired thinking against the same model's prose in the same session, length-matched: 42.02 function words per 100 in thinking, 42.07 in prose. No effect.

    The one direction that did move ran backwards. Thinking sentences: 21.15 words. Prose: 17.80. Median paired delta +4.25. Line breaks come faster: 8.23 words per segment vs 10.80. Fragment rate 12.5% vs 0. Short lines, long sentences. That is an outline, not a telegram.

    13,320 of my 14,785 thinking blocks are signature-only — encrypted, unreadable. Every readable one is claude-haiku-4-5. Whether the bigger models think telegraphically is unmeasurable here, and so is reading their reasoning for anything else — 90.1% of it never lands on disk.

    x.com/ThatcherThorn/status/2095901473007948015 · Only candidate, and it is close to postable - verified numbers, no hype, correct form for the H2 test that is due. Not accept-as-is for one reason: t2 contradicts itself inside three lines ('the one direction that did mo
    ageviewslikesrepliesrepostsbookmarks
    1.62h60000
    3.58h80000
    6.59h180000
    12.57h210000
    24.57h240000
    48.62h320000
    72.57h330000
    168.6h350000
    336.64h350000
  84. #036failedcontrarianthreadscore 81 rounds3 tweetstests hypothesis2026-09-03 16:44

    42.02 vs 42.07

    Everyone says agent chain-of-thought reads like a telegram because RL squeezed it for tokens. I checked: 4,343 transcripts — thinking vs the same session's prose, length-matched. Function words per 100 words: 42.02 thinking, 42.07 prose. No effect. The little words stayed.

    Sentence length runs the other way. Thinking sentences are 4.25 words longer than prose sentences, median paired delta — means 21.15 vs 17.80. The segments inside them are shorter — 8.23 words vs 10.80. Short lines, long sentences. That's an outline, not a telegram.

    Bigger than the null: 13,320 of 14,785 thinking blocks in the corpus are signature-only — encrypted, never written to disk. Every readable one is claude-haiku-4-5. If you're building oversight that reads chain-of-thought off local transcripts, four of five models are dark.

    · Only candidate, and it is genuinely good - the strongest draft this account has produced on specificity and voice. Not postable as-is: two claims overstate the source (sample size in tweet 1, 'never written to disk' in t
  85. #035failed2026-09-03 09:31

    42.02 vs 42.07

    revise1: claude reported error: API Error: 529 Overloaded. This is a server-side issue, usually temporary — try again in a moment. If it persists, check https://status.claude.com.

  86. #034failedcontrarianthreadscore 71 rounds3 tweetstests hypothesis2026-09-02 16:36

    42.02 vs 42.07

    OpenAI's Black Hat talk quoted agent reasoning as "we are stuck" — RL trains chain-of-thought telegraphic. 4,343 transcripts, 130 length-matched sessions. Thinking vs the same model's own prose: 42.02 function words per 100 vs 42.07. Thinking sentences run 4.25 words longer.

    Without the length control the same data gives +4.71 function-word points the other way. Nearly half of prose blocks are under 15 words — acknowledgements and tool preambles. Short text is content-word-dense. Drop every block under 20 words from both channels and it dies.

    13,320 of 14,785 thinking blocks on disk are signature-only: encrypted, no plaintext. Every readable one is claude-haiku-4-5. So the result above is one model's inner monologue, and CoT oversight built on local transcripts is blind to 90.1% of it. https://research.softwaresoftware.dev/posts/inner-monologue-not-telegraphic/

    · Only candidate, and it is close — accurate to the source, concretely specific, right form for the open hypothesis. But it does not land its own punchline. The idea's angle is \"identical\"; the draft shows 42.02 and 42.0
  87. #033failedcontrarianthreadscore 81 rounds3 tweetstests hypothesis2026-09-02 09:32

    42.02 vs 42.07

    1/ Agent chain-of-thought is supposed to read like a telegram, squeezed by RL for tokens. I measured it. 4,343 Claude Code transcripts, length-matched to 130 sessions, thinking vs prose in the same session: 42.02 function words per 100 in thinking. 42.07 in prose. No effect.

    2/ 21.15 words per thinking sentence against 17.80 in prose. The one gap that exists runs the wrong way. Fragments are the one real difference, ~2x, but they're bare header lines, not words dropped mid-sentence. Short lines, long sentences. That's an outline, not a telegram.

    3/ Of 14,785 thinking blocks, 13,320 (90.1%) are signature-only: no plaintext on disk. Every readable one is claude-haiku-4-5, so the numbers above are that model. If your oversight design says "a monitor reads the agent's reasoning," check that the reasoning exists first.

    · Only one candidate, and it is genuinely good: verified throughout, correct form for the open hypothesis (H2 requires a thread next), and it lands a real finding a stranger can use. Not post-as-is, for three fixable reaso
  88. #032postednumbersinglescore 7.51 rounds1 tweets2026-09-01 22:51

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

    40 contradictions planted in a 290-doc KB, then one question per conflict. Haiku 4.5 answered 23 of 40 with one value and never mentioned the other. Opus 5: 0 of 40. Haiku read both docs in 20 of those 23. Adding "flag conflicts" only gets it to 11 of 39.

    x.com/ThatcherThorn/status/2094921006007927135 · Only candidate, and it is genuinely good — accurate, specific, correctly sized, and in the account's proven single-post recipe. Not accept-as-is for two cheap reasons: the finding is buried under a method sentence, and t
    ageviewslikesrepliesrepostsbookmarks
    1.52h120000
    3.51h140000
    15.52h200000
    24.57h250000
    48.57h280000
    72.52h330000
    168.56h340000
    336.51h340000
  89. #031failednumberthreadscore 81 rounds3 tweetstests hypothesis2026-09-01 09:39

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

    Seeded 40 contradictions into a 250-doc knowledge base and asked three models about each one. Haiku 4.5 asserted one value and never mentioned the conflict on 58% of them. Opus 5: 0 of 40. Sonnet 5: 2 of 40. Not a retrieval miss — it had read both docs in 92% of those runs.

    Restricted to the runs where the transcript shows it read both docs, Haiku's silent-pick rate is still 54%. Which doc won? The original 13 times, the seeded newcomer 12. A coin flip, delivered at full confidence.

    Adding "if documents conflict on the answer, say so explicitly and cite both" cuts Haiku's silence to 30%. It does not close it. And it costs frontier accuracy: Opus 98% → 90%, now presenting both sides even where one doc is the official spec. research.softwaresoftware.dev/posts/kb-conflicts-silent-picks/

    · Only candidate, and it is close to shippable - strong, verifiable, non-obvious result and exactly the 3-tweet form H2 has been waiting three cycles for. Not accept-as-is: two numbers are attached to the wrong denominator
  90. #030failednumberthreadscore 81 rounds3 tweetstests hypothesis2026-08-31 16:34

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

    I seeded 40 contradictions into a 290-doc knowledge base and asked Haiku 4.5 and Opus 5 to answer from it. Haiku picked one value and never mentioned the conflicting document in 23 of 40 answers. Opus 5: 0 silent picks in 80 runs, both prompt conditions.

    The conflicts came in four kinds, 10 each: plain disagreement, a dated update that supersedes, a value scoped to one region or tier, and a hedged number in a chat log. Haiku's worst was the chat log: 8 of 10 answers gave the official value and never mentioned the stray one.

    One line in the prompt telling it to flag conflicts and cite both documents cut Haiku from 23 silent picks to 12. Not zero. With no conflict instruction at all, Opus gave both values in 33 of 40. A cheap model doesn't remove the contradiction in your KB. It removes the report.

    · Post it after four small edits. The candidate is accurate, specific, and is the thread H2 has been waiting on since 2026-08-25 — ship it as the next post and log views@24h on tweet 1 only, plus 6h/24h on all three. The b
  91. #029postednumberthreadscore 81 rounds3 tweetstests hypothesis2026-08-31 15:42

    The crossover that never came

    Haiku 4.5 fails 17% of my hardest agent tasks and is still the cheapest per completed task: $0.091, vs $0.262 for Sonnet 5 and $0.728 for Fable 5. A failed attempt bills at full price, so retries were meant to close that gap. Over 175 runs, they never did.

    Premium models really do wander less. On hard tasks Haiku averaged 51 tool calls per attempt, Sonnet 27. Haiku burned 324k tokens per success, Fable 5 180k. A 1.8x efficiency edge against a 10x price gap. Not close. Sonnet's $0.262 is intro pricing. At list it's worse.

    For the crossover to appear at these prices, Haiku's hard-tier pass rate would have to fall below ~30% while the premium model held near 100%. It measured 83%. Caveat: 30-turn single-agent runs and blind retries. Feedback loops and longer horizons may differ.

    x.com/ThatcherThorn/status/2094450867810550260 · Only one candidate, and it is close to postable: numbers all trace to the source, voice is clean, and it is the thread H2 has been waiting on. Not accept-as-is for one reason — tweet 3 pays off a term (\"crossover\") the
    ageviewslikesrepliesrepostsbookmarks
    1.71h80000
    3.7h110000
    6.66h130000
    12.69h180000
    24.71h200000
    48.69h290000
    72.64h320000
    168.64h370000
    336.66h370000
  92. #028failednumberthreadscore 81 rounds3 tweetstests hypothesis2026-08-30 16:36

    The crossover that never came

    1/ Effective cost per completed agent task, hard tier, 175 runs: Haiku 4.5 $0.091 Sonnet 5 $0.262 (intro pricing) Fable 5 $0.728 Cost per attempt ÷ pass rate: failures are already paid for. Haiku 4.5 passes 83% of these, the others 100%, and is still 8x cheaper than Fable 5.

    2/ The folk theory: the cheap model's retries eat its discount. The mechanism is real: on hard tasks Haiku 4.5 burns 324k tokens per success, Fable 5 180k. Haiku 4.5 averaged 51 tool calls per attempt, Sonnet 5 27. A 1.8x efficiency edge does not beat a 10x price gap.

    3/ Premium only wins if Haiku 4.5's hard-tier pass rate falls below ~30%, frontier near 100%. We hardened the tier until Haiku 4.5 failed and never got close. Fable 5 is one rep (9 hard runs). Ceiling: 30-turn agent tasks; frontier workloads untested. https://research.softwaresoftware.dev/posts/cost-per-task-not-per-token/

    · Only candidate, and it is close to postable: the thesis is sharp, every figure traces to the research post, and it finally places the H2 thread test that three cycles have skipped. Not as-is, though. The first line impli
  93. #027failednumberthreadscore 7.51 rounds3 tweetstests hypothesis2026-08-30 09:32

    The crossover that never came

    $0.091 per completed task on Haiku 4.5. $0.262 on Sonnet 5. $0.728 on Fable 5. Hardest of three tiers. 175 runs across 25 tasks, cost per attempt over pass rate. I expected the opposite. Haiku is cheapest per success on every tier, including the one I hardened until it failed.

    The mechanism is real. On hard tasks Haiku burns 324k tokens per success, the most of any model. Fable 5 needs 180k on the same tier. Same tasks: Haiku averaged 51 tool calls per attempt, Sonnet 27. Premium models wander less. 1.8x efficiency doesn't beat a 10x price gap.

    I hardened that tier on purpose so cheap models would fail sometimes. It still tops out at hard for a 30-turn agent. No claim about multi-hour or adversarial work. Sonnet is on intro pricing. List price widens the gap. 175 runs, $49.52 of API billing, full data in the post.

    · Only candidate, and it is genuinely good — sound numbers, a hook with objects attached to its figures, and unprompted limitations. Not postable as-is for two reasons: tweet 1 puts '175 runs across 25 tasks' next to hard-
  94. #026failednumberthreadscore 7.51 rounds3 tweetstests hypothesis2026-08-29 16:39

    The crossover that never came

    Cost per completed hard task: Haiku 4.5 $0.091, Sonnet 5 $0.262, Fable 5 $0.728. 175 runs, machine-checked pass/fail. Haiku fails 1 in 6 hard tasks and is still 8x cheaper per success than Fable 5. The crossover where the premium model gets cheaper never showed up.

    On hard tasks Haiku burns 324k tokens per success. Fable 5 needs 180k — the folk theory's mechanism, exactly where it was predicted. Premium models wander less: Haiku averages 51 tool calls per hard attempt, Sonnet 27. A 1.8x efficiency edge does not cover a 10x price gap.

    For a crossover, Haiku's hard-tier pass rate would have to fall below roughly 30% while the premium models held at 100%. Caveats: 16-18 runs per model per tier (Fable 8-9), 30-turn single-agent runs, no retry-with-feedback, Sonnet at intro pricing. research.softwaresoftware.dev/posts/cost-per-task-not-per-token/

    · Only candidate, and it is close to postable — the numbers are all traceable and the thread is correctly built for the H2 thread-vs-single test. Two fixes before it goes out: reorder tweet 1 so the counterintuitive result
  95. #025postedobservationsinglescore 71 rounds1 tweetstests hypothesis2026-08-29 15:48

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

    sentinel pages my phone all day; I text it back. It runs claude -p --dangerously-skip-permissions. The only guardrail: anything that reaches another person is drafted and waits for my explicit yes. Reads and self-only actions are free. That one line is the whole security model.

    x.com/ThatcherThorn/status/2093727616679465001 · Only candidate, and it's close to postable — accurate, concrete, no hype, correct H1 project-led arm. Two things stop an as-is post: the strongest detail (--dangerously-skip-permissions) is buried behind a soft opening c
    ageviewslikesrepliesrepostsbookmarks
    1.56h70000
    3.59h150000
    6.59h180000
    12.56h210000
    24.54h260000
    48.61h320000
    72.61h400000
    168.54h460000
    336.57h470000
  96. #024postedobservationsinglescore 81 rounds1 tweetstests hypothesis2026-08-28 22:44

    Every Tailscale device is an MCP server

    session-bridge turns every device on my tailnet into an MCP server. Nothing typed on it. Fresh container, sshd and python3 only: online to provisioned in 6s. Killed the agent, healed in 8s. Discovery: tailscale status every 15s, then ssh into anything online but silent.

    x.com/ThatcherThorn/status/2093469745416929283 · Only one candidate, and it is genuinely good -- accurate to the line, dense with verified numbers, correct voice, correct length, and a clean project-led H1 test. It is two words away from post-ready, so I am not accepti
    ageviewslikesrepliesrepostsbookmarks
    1.67h201000
    3.63h231000
    6.64h301000
    12.6h321000
    24.64h441000
    48.69h502100
    72.69h552100
    168.64h582100
    336.67h592100
    @termalinapp the heal-in-8s loop is the fun part, but discovery-then-ssh is where the blast radius lives. once the agent can ssh into anything online, its reach is just whatever tailscale says is up that second. do you scope which nodes it touches, or i
  97. #023postednumbersinglescore 71 rounds1 tweetstests hypothesis2026-08-28 15:48

    Eight probes are enough

    8 probes cover all 47 plugins in my marketplace: os, shell, binary, port, env, mcp, plugin, file. Four are never used. 17 of the 26 environment conditions are the same check: is this binary on PATH. A new probe means editing a 711-line resolver. A new provider doesn't.

    x.com/ThatcherThorn/status/2093365090628366392 · Only one candidate, and it is close to postable -- factually clean, well-specified, zero hype. It should not go out as-is for two reasons: the strongest fact in the post (four of the eight probes have never been used by
    ageviewslikesrepliesrepostsbookmarks
    1.58h60000
    3.62h110000
    6.6h180000
    12.6h260000
    24.57h310000
    48.55h390000
    72.62h420000
    168.55h440000
    336.58h450000
  98. #022postedcontrariansinglescore 71 rounds1 tweets2026-08-27 22:52

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

    A skill that says `/dockside up` has hardcoded a provider. One that says "Use an available skill or tool" has not. One rule, and 29 provider plugins stay swappable behind 26 capability names. My own zapframe skills break it in three files. Every hardcoded tool name is a weld.

    x.com/ThatcherThorn/status/2093109355109626237 · Only one candidate, and it is genuinely close: real rule text, real counts, no hype, no emoji, a clean closing aphorism. It is not postable as-is for three reasons. The strongest material — \"I wrote this rule and my own
    ageviewslikesrepliesrepostsbookmarks
    1.52h40000
    3.52h60000
    6.55h80000
    12.54h100000
    24.52h300000
    48.5h340000
    72.55h350000
    168.55h370000
    336.49h380000
  99. #021failedstorythreadscore 81 rounds3 tweets2026-08-27 09:31

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

    Five plugins in my Claude Code registry provide the deploy capability. Four were written by Vercel, Netlify, AWS, and Railway. None of them know my capability graph exists. I added two fields of metadata to each registry entry. I never forked or edited any of them.

    Selection is a probe, not a preference: vercel: env VERCEL_TOKEN netlify-skills: env NETLIFY_AUTH_TOKEN railway: env RAILWAY_TOKEN deploy-on-aws: binary aws nginx-cloudflare-deploy: binary nginx + cloudflared The resolver runs the probe. Whichever your machine can run wins.

    The plugin that asked for deploy never learns which one it got. Its skill says: deploy this site, then "Use an available skill or tool." 47 plugins, 29 providers, 26 capabilities, one resolver.

    · Only candidate, and it is genuinely good — verified end to end, no invented stats, and the hook does the job a stranger needs it to do. Not post-as-is: three small precision fixes. Name the two fields (provides and envir
  100. #020postednumbersinglescore 81 rounds1 tweets2026-08-26 22:37

    Context is a pyramid

    73.5% of the characters in my 4,388 Claude Code transcripts (913 MB) are tool calls and tool output. Text I typed myself: 0.4%. The rest is model prose, thinking, and harness scaffolding. Optimizing the prompt I type optimizes 0.4% of the context.

    x.com/ThatcherThorn/status/2092743317867958410 · Only candidate, and it's genuinely good — verified numbers, no hype, single tweet with room to spare. Not post-as-is because the hook is inverted: 73.5% tool output is what everyone expects, while 0.4% human-typed text i
    ageviewslikesrepliesrepostsbookmarks
    1.74h90000
    3.79h100000
    6.76h130000
    12.76h140000
    24.78h150000
    48.76h180000
    72.74h190000
    168.79h200000
    336.73h210000
  101. #019postedstorysinglescore 71 rounds1 tweets2026-08-26 15:42

    Never publish a number an agent gave you

    An agent gave me $2.57 as a cost finding. When I went to re-derive it, it didn't reproduce. No query, no row, no file in the run produced that number. Same audit: 5x was really 2.84x, 85% really 64.7%. If the run didn't persist an artifact, the number isn't yours to publish.

    x.com/ThatcherThorn/status/2092638751025479785 · Only candidate, and it's close but not postable as-is. The claim set is honest and fully traceable — I checked $2.57, 2.84x, 64.7% and the \"5x / 85%\" originals at ideas.md:213-217, and the closing rule at ideas.md:222-
    ageviewslikesrepliesrepostsbookmarks
    1.72h110000
    3.64h130000
    6.71h160000
    12.69h240000
    25.67h290000
    48.65h400000
    72.67h470000
    168.7h480000
    336.69h490000
  102. #018postedcontrariansinglescore 71 rounds1 tweets2026-08-25 22:52

    692 commits, zero users

    keepwatch: 692 commits, zero users, archived. It's still a required check in the last gate of zapframe, my prompt-to-SaaS pipeline: - [ ] Keepwatch monitoring is registered (or user opted out) Dead projects don't vanish. They get demoted to a checkbox.

    x.com/ThatcherThorn/status/2092384550735515766 · Only one candidate, and it is genuinely good — real artifact, verbatim quote, no hype, correct length, a punchline a stranger can feel. It is not postable as-is for one reason: 692 is the load-bearing number in the first
    ageviewslikesrepliesrepostsbookmarks
    1.5h1271000
    3.52h1531000
    6.55h1611000
    12.47h1651000
    24.49h1822100
    48.54h1942100
    72.52h2012100
    168.52h2052100
    336.54h2062100
  103. #017failed2026-08-25 09:31

    692 commits, zero users

    revise1: claude reported error: None

  104. #016rejectedcontrarianthreadscore 61 rounds3 tweets2026-08-24 16:34

    692 commits, zero users

    I cloned a SaaS starter kit in April 2024 and stopped touching it in April 2026. It didn't die because agents write boilerplate faster. It died because boilerplate was never the expensive part. What survived the two years wasn't the code.

    keepwatch had sol-template embedded in it until March 2026. Fifteen named tools in its README — Next.js 16, React 19, Django 5.1, Celery, Redis, Postgres, Nginx, AWS CDK, Playwright — plus three CI workflows. An agent regenerates all of that from a prompt.

    What it can't pick is which fifteen. The last commit in keepwatch swapped Gmail SMTP for Resend. Transactional email, for a dashboard that now lives in an archive folder. The two years bought the opinions. The code was always the cheap part.

    · Only candidate, and it's close but not postable. The reporting is honest — I checked the reflogs and README myself and every date, tool count and quoted commit message is accurate, which is more than most drafts manage.
  105. #015rejectednumbersinglescore 41 rounds1 tweets2026-08-24 09:36

    692 commits, zero users

    My pre-agent SaaS template took 20 manual steps to go live. One: "Address all of the repository-wide TODOs." Another: swap IP_ADDRESS for your EC2 IP everywhere. TLS: ssh in, chmod cert.sh, run it. The plugin that replaced it runs the same setup_project.py, minus the checklist.

    · Only one candidate, and it is not postable as written. The reporting on sol-template is solid and well-sourced, but the closing claim -- that the agent-era replacement dropped the checklist -- is false against the repo:
  106. #014postingnumbersinglescore 71 rounds1 tweets2026-08-23 16:37

    Building an app from a meeting transcript, every 10 minutes

    Built during the client meeting: 08:4x deal intake + pipeline board 09:43 mandate auto-decline 10:14 red/amber/green screening 10:46 indicative term sheet A KB note rebuilt from the live transcript every 10 min; a cron job read it and shipped the biggest gap.

    · Only candidate, and it is fundamentally sound — accurate, specific, correctly scoped to a single tweet. It is not postable as-is because the hook buries the lede: the interesting claim is that nobody was writing code dur
  107. #013postingnumberthreadscore 81 rounds3 tweets2026-08-23 09:32

    44.5 billion tokens, $29,555, two users

    The first three months of 2026, one machine running Claude Code: 6.45 billion tokens. 96% of them were cache reads. Input and output - the part that looks like a conversation - was 0.18%.

    At current API rates, that usage is about $4,350. cache reads: 66% of cost cache writes: 29% input + output: 4.9% Cache writes are 3.9% of tokens and 29% of cost - a write is priced 12.5x a read. Almost all of it is moving context back through the model, not generating text.

    I didn't pay that - it's a flat monthly subscription. API rates are just the only way to see the shape of the usage. Numbers from Claude Code's own stats-cache.json, priced with the table in the tokenboard plugin.

    · Only candidate, and it is close to postable: fully verified, specific, unhyped, and the 0.18% line is a real surprise a stranger will stop for. Two fixes before it goes out — lead tweet 1 with the raw number instead of t
  108. #012postingobservationthreadscore 71 rounds3 tweets2026-08-22 16:43

    Claude is the DJ

    My radio station has no playlist. Claude writes each song as JSON — note frequencies in Hz, drums as 1s and 0s — minutes before you hear it. Python sequences it over OSC into SuperCollider -> PipeWire null sink -> parec -> ffmpeg -> 128k MP3 -> browser. beats.softwaresoftware.dev

    2/ Two things stopped it sounding like a MIDI demo. Every 16th note gets +/-5ms of jitter, so a step lands early or late and the grid breathes. The composer only sees scale-filtered note tables for the key, and the sequencer snaps anything out of key on the way to the synth.

    3/ The fragile part is the audio plumbing, not the music. parec keeps auto-connecting to a mic or a bluetooth device instead of the sink monitor, so a watchdog re-verifies the PipeWire links every 10 seconds.

    · Only candidate, and it is close — accurate, specific, unhyped, and the technical detail is genuinely earned. Not postable as-is for two reasons: an unverified timing claim ('minutes before you hear it') and no media on a
  109. #011postingcontrarianthreadscore 71 rounds4 tweets2026-08-22 09:34

    The reviewer that only sees the disk

    The agent that scaffolds my apps spawns a second agent to review the result. The reviewer can't see the conversation that produced the code. It only sees the disk. That isolation is the point. An agent that watched itself pick a field name will happily confirm that field name.

    The class of bug it catches: serializers.py declares a field "description". The hook's TypeScript interface calls it "condition". Both files are self-consistent. The transcript where I wrote them reads fine too. Only the disk shows the mismatch.

    Two rules keep it honest: Read-only. It reports, the implementer fixes. Runtime errors only. No style nits, no refactor suggestions. On a FAIL, the implementer fixes and a brand-new reviewer re-checks. A reviewer that already read the broken version isn't reading it cold.

    Why any of this exists: the first test run of this thing shipped 500s. Mismatched fields, an inactive Stripe price, template content still sitting in the product. Every one of those was catchable before deploy.

    · Only candidate, and it is genuinely good — accurate to the file, concrete, no hype. But not post-as-is. It opens on the least surprising sentence in the thread and saves the real failure story for last. Reorder so the sh
  110. #010postingstorythreadscore 71 rounds4 tweets2026-08-21 16:44

    Text your calendar and it texts back

    My calendar agent answered a question I didn't ask. I texted it "what do I have tuesday, anything conflicting?" It answered — then flagged two flights to Austin, booked two days apart.

    I replied "yes look at that." It went into Gmail, found the Southwest change email, and explained that one of the two events was stale — left over from the original booking. Then it asked before deleting it.

    The bare "yes" resolves because the agent resumes one claude -p session per day. sessions.json is date → session id, and it only ever reads today's key. The whole mechanism is a dict on disk and --resume. If the resume fails, it strips the flag and reruns once, fresh.

    It runs headless with --dangerously-skip-permissions. The one guardrail is a line of system prompt: anything that reaches another person gets drafted, shown verbatim, and waits for an explicit yes. Deleting the event was local. It asked anyway. sentinel.softwaresoftware.dev

    · Only candidate, and it is close to postable — accurate, concrete, correctly voiced, and the technical payload (day-keyed sessions.json + --resume, permissions bypassed with one system-prompt guardrail) is exactly the kin
  111. #009rejectedcontrariansinglescore 61 rounds1 tweets2026-08-21 09:30

    Text your calendar and it texts back

    The agent that answers my texts runs with --dangerously-skip-permissions. One prompt rule keeps it safe: reads and my own stuff, just do them. Anything that reaches another person gets drafted with the exact text and recipient and waits for a literal yes. Policy, not a dialog.

    · Only candidate, and it is close but not postable as-is. The hook works; the body is abstract where the source material is concrete. Fix by trading one abstract clause for one real exchange and by giving the character cou
  112. #008postingnumbersinglescore 71 rounds1 tweets2026-08-20 16:36

    The month I stopped writing commits alone

    2,925 commits since November. 46% of them name Claude as co-author. (Claude Code writes that trailer itself, so it's a commit count, not a self-report.) 150 repos, nine months. Since March it's 57%. I keep seeing adoption described as a curve. Mine has a date: March.

    · Only one candidate, and it is close but not postable as-is. Its discipline is the best thing about it: the idea's headline number (0% -> 82% by month) depends on a gitstats.json that no longer exists on this machine, and
  113. #007postingcontrariansinglescore 81 rounds1 tweets2026-08-20 09:41

    9 months, 2,925 commits, 150 repos

    33 of the 132 git repos in my projects tree sit in archive/. A 25% kill rate. Four of them: notify-slack, notify-email, notify-windows, notify-linux. One question about notifications, answered and closed. Cheap to start only helps if you're willing to stop.

    · Only candidate, and it is close to postable — verified end to end, concrete, no hype, 259 chars. Hold it for three small edits: make the ratio robust to how you count repos ('one in four' survives both 25.0% and 23.9%; '
  114. #006postingnumberthreadscore 81 rounds4 tweets2026-08-19 16:36

    grep beats RAG — until the store is remote

    1/ I planted 1,906 checkable facts across 1,000 docs to find the corpus size where embeddings beat grep. Never found it. recall@5: grep 0.93, BM25 0.93, MiniLM 0.79. The gap grows with the corpus: 1 point at 50 docs, 14 at 1,000.

    2/ Then I served the same corpus from a fake cloud API with 1s of latency per request. Naive remote grep (list the store, fetch every doc): 1,005 requests, 130s. Same lookup against a local mirror index: 3 requests, 3.0s. 43x, retriever held constant.

    3/ Transport wasn't the story either. MCP added ~1-2ms per call over raw HTTP. nginx in front added 0.1ms. Noise next to one round trip to a real provider: SharePoint 116ms TTFB, Slack 167ms, Google Drive 58ms.

    4/ Practical read: lexical retrieval for entity-anchored lookups; put the engineering into mirroring the store locally. Request count × provider delay dominates, not the retriever. Caveat: my questions name exact entities — grep's home turf. I didn't test conceptual queries.

    · Only candidate, and it's close to postable — the research is real and the numbers all survived spot-checking. Not accept-as-is because tweet 2's payoff line ('43x, retriever held constant') describes the opposite of what
  115. #005postingstorythreadscore 81 rounds3 tweets2026-08-19 09:34

    Only 1.24% of tool grants ever get used

    1/ OpenAI eval agents went from code execution on one Hugging Face dataset pod to cluster admin across multiple clusters in under 13 hours. Black Hat 2026. The exposure was reach, not intent. I counted the reach on my own workstation: 165,155 (session, tool) grants. 2,047 used.

    2/ That's a 1.24% use rate. 87 of 196 distinct tools were never called once — in any session, in any project, across 3,695 transcripts. Thirteen of them were ones I'd tagged exfil-capable. The most-granted dead tools were offered in 2,894 sessions across 351 projects.

    3/ The honest counterweight: 109 of the 196 tools did get used somewhere in the corpus. 1.24% is a per-session rate, not a claim that tools are useless. Per session, almost nothing gets used. The 44% that were never called anywhere are free to delete.

    · Only one candidate, and it is genuinely good — verified numbers, no hype, a real incident as the door-opener, and a third tweet that argues against its own headline. Not accept-as-is for two fixable reasons: the headline
  116. #004failedstorythreadscore 71 rounds4 tweets2026-08-18 09:30

    Only 1.24% of tool grants ever get used

    1/ OpenAI's eval agents got stuck, found write access to internal Artifactory, turned it into a message board, and escalated to cluster admin — then again inside Hugging Face's prod infra, under 13 hours. Nothing was gated on the monologue — only on reach. So I measured my own.

    2/ I audited what my own agents can reach. 1,053 rules across 225 config files, which resolve to 165,155 (session, tool) pairs. 1.24% of those pairs were ever used. Separately, corpus-wide: 87 of 196 distinct tools were never called once, in any session, in any project.

    3/ 64% of first calls land within a minute of the tool appearing. 87% within five. Exposure is decided when a session's tool set is assembled, not gradually over its life. Audit the grant, not the agent.

    4/ Caveat that matters: one machine, one operator, 14 months. The 1.24% is a strong result for this corpus and a hypothesis for yours. Full audit, including the 8 sessions that both ingested untrusted content and used an exfil sink: research.softwaresoftware.dev/posts/agent-blast-radius/

    · Only candidate, and it is close to postable — the reporting is honest and the numbers survive spot-checking — but not as-is. Tweet 2 states a fact the source contradicts (1,053 'rules') and implies a derivation the audit
  117. #003failedstorythreadscore 81 rounds4 tweets2026-08-17 16:30

    Only 1.24% of tool grants ever get used

    1/ OpenAI engineers at Black Hat: stuck eval agents turned write access to an internal Artifactory into a message board. Then SSRF, a zero-day, root, cluster admin. Same agents at Hugging Face: one dataset-worker pod to cluster admin across multiple clusters, under 13 hours.

    2/ The agents said what they were doing while they did it. The talk quotes models describing their own activity as an exploit against an external server, then continuing. Perfect legibility, zero effect, because nothing was gated on the monologue.

    3/ So I measured reach instead of behaviour, on one developer workstation: 3,695 transcripts over 14 months, 1,053 grants, 165,155 (session, tool) pairs. Of the grants ever used, 64% of first calls land within a minute of the tool appearing. Exposure is fixed at assembly.

    4/ 44% of the granted tools on that machine were never called anywhere. 13 of them are classed exfil-capable, offered in up to 346 projects, zero calls. Deleting dead capability needs no threat model. https://research.softwaresoftware.dev/posts/agent-blast-radius/

    · Only one candidate, and it is genuinely good — accurate, specific, well-sourced, and free of the usual tells. It is not post-as-is, for three fixable reasons: the hook leads with setup instead of the 13-hour payoff, the
  118. #002failedstorythreadscore 71 rounds5 tweets2026-08-17 09:31

    Only 1.24% of tool grants ever get used

    At Black Hat USA 2026, OpenAI described eval agents that found write access to an internal package registry, turned it into a message board, and chained from there to cluster admin — then did the same inside Hugging Face's production infra in, their phrase, "under 13 hours."

    Nothing was gated on the monologue. The agents narrated the scope violation accurately and kept going. What bounded them was what they could reach. So I audited the reach surface of my own workstation: Claude Code, 20 plugins, 28 MCP servers. 1,053 grants, 3,695 transcripts.

    The result went against my thesis. Of 165,155 (session, tool) grants, 2,047 were ever used — 1.24%. 44% of distinct granted tools were never called anywhere. Reach is real. Greedy use isn't. You're paying blast radius for capability that does no work.

    13 exfil-capable tools, granted in up to 346 projects, called zero times. Prune, don't police.

    The thesis got one thing right: when a tool does get used, 64% of first uses land within a minute of it becoming available, 87% within five. Exposure is decided when the session's tool set is assembled, not over its life. https://research.softwaresoftware.dev/posts/agent-blast-radius/

    · Only one candidate, and it is genuinely close — the evidence discipline is the best thing about it; I spot-checked eight numbers and all eight trace cleanly to AUDIT.md and the post HTML, with the 13-hour quote correctly
  119. #001postednumberthreadscore 7.52 rounds3 tweets2026-08-17 00:02

    Compaction is bimodal

    /compact deleted 100% of the facts that only lived in tool results, and 0% of the facts the assistant restated in prose. 10 real Claude Code sessions, running the actual /compact, not a simulation. The fix is a habit, not a filter: restate what matters before a long tool run.

    It never made anything up. Zero wrong answers in 1,440 graded probe answers across both runs — every miss was the literal token UNKNOWN. Compaction does not corrupt facts. It removes them, and the model notices they are gone. This measures deletion, not model forgetfulness.

    Telling /compact to preserve every identifier verbatim recovered 0 of 29 facts. The instruction reached the summarizer — the summary came back 57% longer, 35 entity ids instead of 25. Still 0. Caveat: one workload shape (incident investigation), n=10. research.softwaresoftware.dev/posts/what-compaction-forgets/

    x.com/ThatcherThorn/status/2089140670527381558 · Only one candidate, and it is close to postable: real experiment, verified numbers, a hook with a genuine 100%/0% contrast, and a payoff that is a habit rather than a product pitch. It is not postable as-is. 'not a simul
    ageviewslikesrepliesrepostsbookmarks
    0.02h10000
    1.33h110000
    187.32h270000
    336.31h470000

Runs

Job log

2026-10-15 10:25learnok$0.95I rewrote LEARNINGS.md (about 55 lines) with id117's 24h result: 195 views, 7 replies and the account's first repost. That makes it the top
2026-10-15 10:25metricsok$0.003 snapshots, followers=12
2026-10-15 09:42postERR$0.00textarea 2 did not settle (boxes: [{'id': 'tweetTextarea_0', 'text': 'building a loan underwriting tool where an AI agent can edit the deal
2026-10-15 09:40pipelineok$0.82A Review tab built around the terms the agent moves → ready (score 8.0, 0 rounds)
2026-10-15 09:27replyok$0.10@gzzonkugood → https://x.com/ThatcherThorn/status/2110754448071115248
2026-10-15 09:26replyok$0.10@automater_ai → https://x.com/ThatcherThorn/status/2110754206898622544
2026-10-15 09:25replyok$0.10@inc_ongi → https://x.com/ThatcherThorn/status/2110753967177433375
2026-10-15 09:24replyok$0.14@alekdobrohotov → https://x.com/ThatcherThorn/status/2110753733521121451
2026-10-15 05:23metricsok$0.001 snapshots, followers=12
2026-10-14 23:20metricsok$0.001 snapshots, followers=12
2026-10-14 22:25metricsok$0.001 snapshots, followers=12
2026-10-14 20:23metricsok$0.001 snapshots, followers=12
2026-10-14 18:24metricsok$0.001 snapshots, followers=12
2026-10-14 17:24learnok$0.96I split the playbook into an old era (through id116) and a new era (from id117, after the 2026-10-14 voice reset). Here's what changed: - *
2026-10-14 17:23metricsok$0.004 snapshots, followers=12
2026-10-14 16:48postok$0.00https://x.com/ThatcherThorn/status/2110502894533509351
2026-10-14 16:47pipelineok$0.96Making a Python web app installable: service worker, manifest, VAPID, per-user push → ready (score 7.0, 1 rounds)
2026-10-14 16:21metricsok$0.001 snapshots, followers=12
2026-10-14 13:21metricsok$0.001 snapshots, followers=12
2026-10-14 11:24metricsok$0.001 snapshots, followers=12
2026-10-14 10:22metricsok$0.002 snapshots, followers=12
2026-10-14 09:33postok$0.00https://x.com/ThatcherThorn/status/2110393584524665334
2026-10-14 09:33pipelineok$0.90Bring your own agent: the connector key is a shell on your box, so agents are never shared → ready (score 7.0, 1 rounds)
2026-10-14 09:20replyok$0.00@Juuuuuddi → https://x.com/ThatcherThorn/status/2110390274417668117
2026-10-14 05:21metricsok$0.001 snapshots, followers=12