🏑


  1. July 11, 2026
    1. πŸ”— anthropics/claude-code v2.1.207 release

      What's changed

      • Auto mode is now available without CLAUDE_CODE_ENABLE_AUTO_MODE opt-in on Bedrock, Vertex AI, and Foundry; disable via disableAutoMode in settings
      • Fixed the terminal freezing and keystrokes lagging while streaming responses containing very long lists, tables, paragraphs, or code blocks
      • Fixed remote managed settings from a non-interactive run (claude -p, the SDK) being permanently recorded as consented without ever showing the security consent dialog
      • Fixed spurious prompt-injection warnings triggered by benign system-generated conversation updates
      • Fixed the auto-updater overwriting a custom launcher script or symlink at ~/.local/bin/claude on every release; /doctor now reports an externally managed launcher
      • Fixed compound commands with cd prompting for permission when the only output redirect was to /dev/null
      • Fixed the transcript jumping above the start of the answer when a response finishes streaming
      • Fixed extensions.worktreeConfig being left in the repo's .git/config (breaking go-git tools like tea) after the last worktree.sparsePaths worktree was removed
      • Fixed malformed bracket patterns in rules globs, skill paths, .ignore, and .worktreeinclude breaking file reads, file suggestions, and worktree creation
      • Fixed a crash loop in agent teams where a malformed teammate mailbox message caused repeated errors every second until the mailbox file was manually deleted
      • Fixed background sessions auto-named by accepting a plan not showing that name on their agent-view row
      • Fixed background sessions that entered a git worktree resuming blank after a cold reopen from the agent list
      • Fixed Remote Control task status updates being lost when the connection recovered from a network interruption or credential refresh
      • Fixed Remote Control sessions hosted by the desktop app not showing background agent and workflow progress on mobile and web
      • Fixed Deep research runs labeling every Fetch-phase agent "unknown" β€” chips now show the source hostname
      • Fixed Bedrock repeatedly requesting fresh AWS SSO credentials from IAM Identity Center on every API request
      • Improved agent view: pasting the same text again now expands the collapsed [Pasted text #N] placeholder instead of adding a second one
      • Improved agent view: blocked session peeks now lead with the question and show a worded staleness clock (waiting 3m) instead of the same timestamp twice
      • Changed Bedrock, Vertex, and Claude Platform on AWS to default to Claude Opus 4.8
      • Changed auto mode to no longer read autoMode from .claude/settings.local.json (repo-resident); use ~/.claude/settings.json instead
      • Fixed an indefinite hang on Windows when AWS credential resolution stalls (e.g. a stuck credential_process): the 60-second stall guard now fires instead of waiting forever.
      • Plugin hooks/monitors/MCP headersHelper: ${user_config.*} in shell-form commands is now rejected (shell-injection fix). Hooks: use exec form (args array) or $CLAUDE_PLUGIN_OPTION_<KEY>; monitors and headersHelper: read the value inside the script (config file or the server's env block).
      • Plugin option values (pluginConfigs) are no longer read from project-level .claude/settings.json; only user, --settings, and managed settings are honored
      • Fixed /usage-credits amount inputs silently stripping malformed values (e.g. a pasted timestamp) to digits; malformed amounts are now rejected with an error, and amounts over $1,000 require a typed confirmation
  2. July 10, 2026
    1. πŸ”— HexRaysSA/plugin-repository commits sync repo: +1 plugin, +2 releases rss
      sync repo: +1 plugin, +2 releases
      
      ## New plugins
      - [mcrit-ida](https://github.com/danielplohmann/mcrit-plugin) (1.1.7)
      
      ## New releases
      - [ida-rpc](https://github.com/bkerler/ida_rpc): 0.1.5
      
    2. πŸ”— backnotprop/plannotator v0.23.0 release

      Follow @plannotator on X for updates

      Missed recent releases? Release | Highlights
      ---|---
      v0.22.0 | Git-status "All changes" default review view, Commits panel with per-commit diffs, Guided Review, Pi + GitHub Copilot CLI review engines
      v0.21.4 | Markdown math rendering, PR Overview panel with annotatable description and comments, agent instructions in code review, media parsing fixes
      v0.21.3 | File comments in code review, unified click-to-highlight comments, VS Code clipboard/keyboard bridge, Codex Ask AI on app-server transport, CLI subcommand help
      v0.21.2 | Custom reviews as Agent Skills, Cursor + OpenCode review engines, whole-file/general findings, deleted-annotation fix, Codex Ask AI outside git repos
      v0.21.1 | Annotate-last blank-page fix on multi-message sessions
      v0.21.0 | Direct document editing in annotate mode, live git-status file tree, in-app agent terminal, open files in external apps, HTML renders as HTML
      v0.20.3 | Annotations no longer lost when clicking away, off-screen indicator for open comments
      v0.20.2 | Pierre CodeView all-files review, large-PR pipeline and instant-open checkout, unified agent engine selection, Pi programmatic plan mode
      v0.20.1 | Pi extension install hotfix (pinned @pierre/diffs after a broken upstream release)
      v0.20.0 | Multi-repo workspace reviews, semantic diff overview, UI 2.0 themes and plan look chooser, leaner single-source skill install
      v0.19.27 | Kiro CLI integration, Glimpse native window, annotate-last message picker


      What's New in v0.23.0

      This is a community release: 22 PRs, seven of them authored by community contributors, five of whom are contributing for the first time. Plan approval works again on current Claude Code versions, annotate mode gains the version diff that plan mode has always had, the installer learns a binary-only mode, and a wave of Windows, OpenCode, and WebKit fixes lands. The whole changeset went through a multi-day adversarial QA pass β€” every commit audited, installers exercised end-to-end β€” before tagging.

      Plan approval works again on Claude Code 2.1.199+

      Claude Code 2.1.199 added a guard that discards a PermissionRequest allow decision for ExitPlanMode when updatedInput is absent. The result: clicking Approve in the plan review UI closed the page, but the built-in approval dialog reappeared in the terminal as if nothing happened. Deny was unaffected, which made the failure look like a Plannotator bug rather than a protocol change.

      The hook now echoes the plan back as updatedInput alongside the allow decision, which satisfies the new guard on 2.1.199+ and is ignored harmlessly by older versions. If plan approval stopped working for you recently, this release fixes it.

      PR #1008 by @flex-yj- kim, closing #995 reported by @axelboman277.

      Annotate mode: version diff for your files

      Plan mode has always shown a +N/-M badge when a plan is resubmitted, with a highlighted diff of what changed between versions. Annotate mode had the same diff UI sitting unused, because the annotate server never tracked history. Now it does: opening a .md or .html file saves a version keyed by file path, and re-opening the same file later shows exactly what changed since you last annotated it β€” same badge, same rendered diff, same Version Browser in the sidebar.

      HTML files annotated with --render-html get the diff as the real rendered page with inline insertion/deletion highlights, not a wall of markup. History is stored under ~/.plannotator/history/; if you'd rather keep annotate sessions stateless, disable it with PLANNOTATOR_ANNOTATE_HISTORY=0 or { "annotateHistory": false } in ~/.plannotator/config.json. A follow-up hardening in this release also makes the history write best-effort: an unwritable data directory degrades to a normal no-diff session instead of failing to open.

      PR #961 by @egouilliard-leyton, who also proposed the feature in #960.

      Binary-only install with --minimal

      The installer writes more than the binary: the sem semantic-diff sidecar, the agent-terminal runtime, and per-agent skills, hooks, and commands for Claude, Codex, OpenCode, Gemini, and Kiro. For users who want none of that, there was no way to opt out. Now there is:

      curl -fsSL https://plannotator.ai/install.sh | bash -s -- --minimal
      

      --minimal (alias --binary-only, env var PLANNOTATOR_MINIMAL=1) installs the plannotator binary and stops β€” no sidecars, no skills, no hooks, no config writes. It works identically across install.sh, install.ps1, and install.cmd, and --no-minimal overrides a persistently exported env var. The mode is non-destructive: running it over an existing full install upgrades the binary and leaves everything else alone.

      PR #989 by @Staninna, closing #977 reported by @wauxhall.

      Reviews post as you, without attribution

      Submitting a PR review to GitHub or GitLab used to append "Review from Plannotator" to the review body. That text is gone. Your general comment and file-scoped feedback post exactly as you wrote them; when GitHub requires a top-level body for an inline-only comment review, a neutral "See inline comments." is used instead; approvals and GitLab inline-only discussions stay bodyless.

      PR #1033 by @backnotprop, superseding #1026 by @leoreisdias, who pushed for the change.

      Windows: hooks survive spaces in your install path, installers render

      cleanly

      Two classes of Windows breakage are fixed. First, the generated Claude Code hook commands embedded the absolute exe path unquoted β€” on any machine whose profile path contains a space (C:\Users\John Smith\...), the hook command word-split and plan review silently never intercepted. Both Windows installers now quote the path, and the install test harness pins it.

      Second, PR #1021 by @ShiroKSH fixed a broad set of Windows edge cases: the PowerShell installer now parses correctly under stock Windows PowerShell 5.1 (all non-ASCII characters removed, with a regression test), Amp workspace and binary paths normalize across platforms, Ask AI server turns abort cleanly when sessions reset, and Pi archive/config behaviors match Bun's. The same ASCII treatment was then applied to install.cmd, whose status messages rendered as mojibake on default Windows code pages.

      Annotate folders: filter the file tree

      Annotating a folder now gives you a filter row above the file tree. Type any set of words and they AND-match against file names and paths; matching folders expand automatically while you type, and Escape clears the filter before it closes the browser. Behind it, the folder scan is capped at 5,000 files (configurable via PLANNOTATOR_FILE_BROWSER_MAX_FILES) so a giant monorepo can't hang the browser β€” and your own modified and untracked files are seeded into the tree first, so the files you just edited always appear no matter how large the folder is.

      PRs #1027 and #1022 by @backnotprop.

      OpenCode: session URLs you can actually see

      Remote OpenCode users (SSH, devcontainers) periodically hit the same wall: the plan or review server starts, but the URL to open it never appears anywhere visible. The root cause turned out to be structural β€” every URL was routed through client.app.log, which OpenCode writes to its server log file, never the TUI. Session URLs now also surface as TUI toast notifications, delivered through the SDK's visible channel, deduplicated per session, and harmless on older OpenCode hosts that predate the toast endpoint.

      Two more OpenCode fixes ride along: model dropdown labels are disambiguated by provider (#1024 by @yusufemreboyraz, closing #988 reported by @ak64th), so deepseek-v4-pro from DeepSeek and OpenRouter are tellable apart β€” and annotate version history is now scoped per project on OpenCode, matching the other runtimes.

      Additional Changes

      • Comment editor focuses on open in WebKit hosts β€” selecting text opens the comment editor with the textarea actually focused; WKWebView hosts (like the Glimpse native window) previously required tabbing into it. PR #1031 by @BrandonNoad.
      • Annotate sidebar keyboard shortcuts β€” toggle the Contents and Files panels from the keyboard, with the bindings listed in Settings while in annotate mode. PR #986 by @leoreisdias.
      • GPT-5.6 model family in the Codex job selector β€” gpt-5.6 (sol), gpt-5.6-terra, and gpt-5.6-luna are selectable for review jobs, Code Tours, and Guided Reviews. Ask AI discovers Codex models dynamically and needed no change.
      • First-time PR reviewers get a destination pointer β€” a one-time spotlight on the Agent / GitHub switcher explains that feedback can post to the PR or go to your agent session, and that double-tapping Alt toggles it.
      • PR comments render tables and inline video β€” GitHub PR descriptions, comments, and commit messages with markdown tables or video attachments now render properly in the review Overview. PR #1007.
      • HTML files render untouched β€” annotating an .html file renders the document byte-for-byte in a sandboxed frame instead of normalizing it. PR #1023.
      • Resize handles: click to collapse β€” panel resize handles collapse on click along their full height, with a cursor hint, and the hover highlight can be suppressed by hosts. PR #1028.
      • Read-only data directories can't block sessions β€” an unwritable ~/.plannotator (read-only mount, full disk) now degrades annotate history and session discovery gracefully instead of failing startup.
      • Component library migrated to Base UI β€” the plan and review UIs moved from Radix to Base UI with behavior preserved, part of publishing the document UI as reusable packages. PRs #957, #1013, #1014, #1017.
      • plannotator.ai/code-review β€” a dedicated landing page for the code review side of Plannotator, with an inline Guided Review demo. PRs #1003, #1006, #1012.

      Install / Update

      macOS / Linux:

      curl -fsSL https://plannotator.ai/install.sh | bash
      

      Windows:

      irm https://plannotator.ai/install.ps1 | iex
      

      Extra skills (compound, setup-goal, visual-explainer), opt-in:

      npx skills add backnotprop/plannotator/apps/skills/extra
      

      Claude Code Plugin: Run /plugin in Claude Code, find plannotator , and click "Update now".

      OpenCode: Clear cache and restart:

      rm -rf ~/.bun/install/cache/@plannotator
      

      Then in opencode.json:

      {
        "plugin": ["@plannotator/opencode@latest"]
      }
      

      Pi: Install or update the extension:

      pi install npm:@plannotator/pi-extension
      

      Droid: Install via the plugin marketplace:

      droid plugin marketplace add backnotprop/plannotator
      droid plugin install plannotator@plannotator
      

      Amp: Install the CLI first, then copy the plugin:

      mkdir -p ~/.config/amp/plugins
      curl -fsSL https://raw.githubusercontent.com/backnotprop/plannotator/main/apps/amp-plugin/plannotator.ts \
        -o ~/.config/amp/plugins/plannotator.ts
      

      Kiro CLI: The installer auto-detects Kiro and installs skills automatically. After installing the CLI, launch with:

      kiro-cli chat --agent plannotator
      

      Upgrading from before v0.20.0? Read the v0.20.0 release notes first; that release changed how skills install.


      What's Changed

      New Contributors

      Contributors

      @flex-yj-kim tracked the Claude Code 2.1.199 protocol change to its exact guard and shipped the updatedInput echo that makes plan approval work again (#1008), a fix most of the plugin's users will feel immediately.

      @egouilliard-leyton proposed the annotate version diff in #960 and then built it (#961), including the rendered-HTML diff with inline highlights. First contribution.

      @Staninna built the --minimal install mode across all three installer scripts (#989). First contribution.

      @ShiroKSH swept a wide set of Windows edge cases in one PR (#1021) β€” installer encoding, path normalization, Ask AI abort behavior, and Pi parity details. First contribution.

      @yusufemreboyraz fixed the ambiguous OpenCode model labels (#1024). First contribution.

      @BrandonNoad root-caused the WebKit focus quirk and moved the comment editor's focus to a ref callback (#1031). First contribution.

      @leoreisdias added the annotate sidebar shortcuts (#986) and drove the removal of review attribution β€” his #1026 shaped the approach that shipped in #1033.

      Community members who reported issues that drove changes in this release:

      • @axelboman277: #995 (plan approval silently ignored on Claude Code β‰₯ 2.1.200), with @blimmer adding reproduction detail in the discussion
      • @wauxhall: #977 (installer writes state the user didn't ask for)
      • @ak64th: #988 (duplicate OpenCode model labels across providers)

      Full Changelog : v0.22.0...v0.23.0

    3. πŸ”— Anton Zhiyanov Go-flavored concurrency in C rss

      Go's concurrency is one of the main reasons people like the language. You write go f(), send values through channels, and the runtime scheduler runs thousands of goroutines on just a few OS threads. It feels effortless.

      None of that machinery exists in C. Which made me wonder: how close can you get to Go's concurrency model using only POSIX threads? Obviously, native OS threads can't match the efficiency of lightweight goroutines, but what is the actual cost, when does it become a problem, and is there any way to at least partially avoid it?

      I ran into these questions while adding concurrency to Solod (So), a strict subset of Go that translates to plain C, with no runtime and no garbage collector. In the end, I came to the conclusion that you can do quite a lot with pthreads β€” as long as you're honest about the tradeoffs.

      This post is about the POSIX threads-based concurrency model I chose, the benefits it offers, and its limitations.

      Mutex/Cond β€’ Atomics β€’ Pool β€’ Channel β€’ Performance β€’ Design β€’ Wrapping up

      Mutex/Cond Everything in So's concurrency stack is built on two basic POSIX primitives: the mutex and the condition variable. sync.Mutex is a thin wrapper around pthread_mutex_t: // Extracted from So's stdlib source code. type Mutex struct { mu pthread_mutex_t } func (m *Mutex) Lock() { rc := pthread_mutex_lock(&m.mu) if rc != 0 { panic("sync: Mutex.Lock failed") } } Since So translates to C, this is basically a struct that holds a pthread_mutex_t and a function that calls pthread_mutex_lock. Here's the transpiler output: // The translated C code. typedef struct sync_Mutex { pthread_mutex_t mu; } sync_Mutex; void sync_Mutex_Lock(sync_Mutex* m) { int rc = pthread_mutex_lock(&m->mu); if (rc != 0) { so_panic("sync: Mutex.Lock failed"); } } That is the whole translation β€” the generated C is a near-mechanical mirror of the So code, only noisier. From here on, I'll mainly show the So version, but I'll also provide the C code for those who are interested. There's nothing exciting here: sync.Mutex is a pthread mutex wrapper that panics if something goes wrong (which is rare). The companion primitive is sync.Cond, a wrapper around pthread_cond_t. It's the standard "wait until a condition holds" tool, associated with a mutex: type Cond struct // wraps pthread_cond_t + pthread_mutex_t func (c *Cond) Wait() // wraps pthread_cond_wait func (c *Cond) Signal() // wraps pthread_cond_signal func (c *Cond) Broadcast() // wraps pthread_cond_broadcast Show the translated C code typedef struct sync_Cond { pthread_cond_t cond; sync_Mutex* mu; } sync_Cond; void sync_Cond_Wait(sync_Cond* c); // wraps pthread_cond_wait void sync_Cond_Signal(sync_Cond* c); // wraps pthread_cond_signal void sync_Cond_Broadcast(sync_Cond* c); // wraps pthread_cond_broadcast These two types β€” Mutex and Cond β€” are the foundation. Other concurrency tools β€” Once, the thread pool, channels β€” are built using a mutex and one or more condition variables. This has several effects on performance, as we'll see later. Atomics Not everything needs a lock. So's sync/atomic mirrors Go's: Bool, Int32, Int64, Uint32, Uint64, and a generic Pointer[T], all with Load, Store, Swap, and CompareAndSwap methods. The nice thing is that these don't need pthreads at all. They map directly to the C compiler's __atomic builtins β€” the same hardware instructions that Go's compiler emits. So there's no reason for them to be any slower, and they're not: Atomic op | Go | So | Winner ---|---|---|--- Load | 2ns | 2ns | ~same Store | 2ns | 2ns | ~same CompareAndSwap | 13ns | 13ns | ~same Each number is the cost of one operation on a single thread. sync.Once is a good example of using atomics effectively. Its fast path only needs a single atomic load β€” after the given function runs, every future call to Do checks a flag and returns: type Once struct { mu Mutex done atomic.Bool } // Do calls f if and only if Do is being called // for the first time for this o. func (o *Once) Do(f func()) { if o.done.Load() { // lock-free fast path return } // slow path... } Show the translated C code typedef struct sync_Once { sync_Mutex mu; atomic_Bool done; } sync_Once; // Do calls f if and only if Do is being called // for the first time for this o. void sync_Once_Do(sync_Once* o, void (*f)()) { if (atomic_Bool_Load(&o->done)) { // lock-free fast path return; } // slow path... } Worker pool To actually run code concurrently, you need threads. The conc.Thread type wraps pthread_t and its related functions: type Thread struct // wraps pthread_t func (th Thread) Wait() any // wraps pthread_join func (th Thread) Detach() // wraps pthread_detach Show the translated C code typedef struct conc_Thread { pthread_t t; } conc_Thread; void* conc_Thread_Wait(conc_Thread th); // wraps pthread_join void conc_Thread_Detach(conc_Thread th); // wraps pthread_detach Consider this conc.Go function: // Go launches an OS thread that runs fn(arg) and returns a handle to it. func Go(entry func(any) any, arg any) Thread { var th Thread rc := pthread_create(&th.t, nil, entry, arg) // ... } Show the translated C code // Go launches an OS thread that runs fn(arg) and returns a handle to it. // `any` in So translates to `void*` in C. conc_Thread conc_Go(void* (*entry)(void*), void* arg) { conc_Thread th = {0}; int rc = pthread_create(&th.t, NULL, entry, arg); // ... } Usage example: func work(arg any) any { acc := arg.(*Account) // ... } func main() { var acc Account th := conc.Go(work, &acc) // ... do other work concurrently ... th.Wait() // work is complete once Wait returns } Show the translated C code void* work(void* arg) { main_Account* acc = (main_Account*)arg; // ... } int main(void) { main_Account acc = {0}; conc_Thread th = conc_Go(work, &acc); // ... do other work concurrently ... conc_Thread_Wait(th); // work is complete once Wait returns } It might look like go work(&acc), but that's just on the surface. conc.Go starts an actual OS thread, not a goroutine. You have to eventually call Wait to join or Detach it, or else its resources will leak. Also, OS threads are expensive to create β€” they're nothing like Go's goroutines, which only need a few kilobytes of stack and start up in nanoseconds. That's exactly why you usually don't want to call Go inside a loop. For tasks that are short-lived or happen often, it's better to use a pool of long- lived worker threads and send tasks to them. conc.Pool to the rescue: Worker thread pool in So β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Task 1 β”‚ β”‚ Task 2 β”‚...β”‚ Task M β”‚ M tasks β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ conc.Pool β”‚ coordinator β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Thrd 1 β”‚ β”‚ Thrd 2 β”‚...β”‚ Thrd N β”‚ N threads, N << M β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ OS scheduler β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ Usage example: type Task struct { in int out int } func square(arg any) { task := arg.(*Task) task.out = task.in * task.in } func main() { tasks := make([]Task, 10) opts := conc.PoolOpts{NumThreads: 2} pool := conc.NewPool(mem.System, opts) defer pool.Free() for i := range tasks { tasks[i].in = i pool.Go(square, &tasks[i]) } pool.Wait() } Show the translated C code typedef struct main_Task { so_int in; so_int out; } main_Task; void square(void* arg) { main_Task* task = (main_Task*)arg; task->out = task->in * task->in; } int main(void) { so_Slice tasks = so_make_slice(main_Task, 10, 10); conc_PoolOpts opts = (conc_PoolOpts){.NumThreads = 2}; conc_Pool* pool = conc_NewPool(mem_System, opts); for (so_int i = 0; i < so_len(tasks); i++) { // so_at is a generic macro to get the i-th element of a // specific type (main_Task here) from a type-erased slice. // Here we're getting the i-th task from the tasks slice. so_at(main_Task, tasks, i).in = i; conc_Pool_Go(pool, square, &so_at(main_Task, tasks, i)); } conc_Pool_Wait(pool); conc_Pool_Free(pool); } The first argument to NewPool, mem.System, is a memory allocator. Solod avoids hidden allocations, so anything that needs memory takes an allocator explicitly β€” here it backs the pool's task queue. Under the hood, a Pool is a fixed group of worker threads that pull tasks from a shared queue (a ring buffer). It uses one mutex and a few condition variables: // Pool is a bounded pool of worker threads with a wait queue // which execute tasks of the form func(any). type Pool struct { alloc mem.Allocator mu sync.Mutex notEmpty sync.Cond // signaled when a task is enqueued notFull sync.Cond // signaled when a slot frees allDone sync.Cond // broadcast when no task is in flight workers []Thread queue []task // ring buffer of submitted tasks active int // tasks submitted but not yet finished stopped bool // set by Free to drain and exit } // NewPool creates a pool with a given number // of worker threads and starts them. func NewPool(alloc mem.Allocator, opts PoolOpts) *Pool // Go submits a task for execution, blocking while the queue is full. func (p *Pool) Go(fn func(any), arg any) // Wait blocks until all submitted tasks finish. func (p *Pool) Wait() Show the translated C code // Pool is a bounded pool of worker threads with a wait queue // which execute tasks of the form func(any). typedef struct conc_Pool { mem_Allocator alloc; sync_Mutex mu; sync_Cond notEmpty; // signaled when a task is enqueued sync_Cond notFull; // signaled when a slot frees sync_Cond allDone; // broadcast when no task is in flight so_Slice workers; so_Slice queue; // ring buffer of submitted tasks so_int active; // tasks submitted but not yet finished bool stopped; // set by Free to drain and exit } conc_Pool; conc_Pool* conc_NewPool(mem_Allocator alloc, conc_PoolOpts opts); void conc_Pool_Go(conc_Pool* p, void (*fn)(void*), void* arg); void conc_Pool_Wait(conc_Pool* p); notEmpty wakes up a worker when there are tasks to do, notFull applies back-pressure when the queue is full, and allDone lets Wait know when everything is finished. It's a classic producer-consumer setup, about 200 lines of code, and there's nothing fancy about it. The heart of the pool is the worker loop. Each thread blocks until a task appears, runs it outside the lock so workers execute in parallel, then records that it finished: // workerMain runs on every pool thread: pull a task, run it, repeat. func workerMain(arg any) any { p := arg.(*Pool) for { p.mu.Lock() for p.qempty() && !p.stopped { p.notEmpty.Wait() // sleep until a task is enqueued } if p.qempty() && p.stopped { p.mu.Unlock() break // queue drained and pool shutting down } t := p.qpop() p.notFull.Signal() // a slot freed for a waiting submitter p.mu.Unlock() t.fn(t.arg) // run the task with the lock released p.mu.Lock() p.active-- if p.active == 0 { p.allDone.Broadcast() // wake anyone parked in Wait } p.mu.Unlock() } return nil } Show the translated C code // workerMain runs on every pool thread: pull a task, run it, repeat. static void* workerMain(void* arg) { conc_Pool* p = (conc_Pool*)arg; for (;;) { sync_Mutex_Lock(&p->mu); for (; conc_Pool_qempty(p) && !p->stopped;) { sync_Cond_Wait(&p->notEmpty); // sleep until a task is enqueued } if (conc_Pool_qempty(p) && p->stopped) { sync_Mutex_Unlock(&p->mu); break; // queue drained and pool shutting down } task t = conc_Pool_qpop(p); sync_Cond_Signal(&p->notFull); // a slot freed for a waiting submitter sync_Mutex_Unlock(&p->mu); t.fn(t.arg); // run the task with the lock released sync_Mutex_Lock(&p->mu); p->active--; if (p->active == 0) { sync_Cond_Broadcast(&p->allDone); // wake anyone parked in Wait } sync_Mutex_Unlock(&p->mu); } return NULL; } This is what separates a pool from a plain queue. Pool.Go bumps active as it enqueues; each worker decrements it after running a task, and the last one out broadcasts allDone. Pool.Wait sleeps until the count hits zero: // Wait blocks until every submitted task has finished. func (p *Pool) Wait() { p.mu.Lock() for p.active != 0 { p.allDone.Wait() } p.mu.Unlock() } Show the translated C code // Wait blocks until every submitted task has finished. void conc_Pool_Wait(conc_Pool* p) { sync_Mutex_Lock(&p->mu); for (; p->active != 0;) { sync_Cond_Wait(&p->allDone); } sync_Mutex_Unlock(&p->mu); } The tradeoff is that the number of worker threads is fixed. In Go, a program can handle thousands of concurrent I/O waits because blocked goroutines use very little memory. A So pool can't do this β€” if all N workers are parked on a blocking syscall, the pool is stalled until one returns. You have to set the pool size based on the workload, instead of letting the runtime manage it for you. Channel Channels are an important part of Go's concurrency model, and So's conc.Chan[T] gives you something quite similar. Just like in Go, it passes values by copy and comes in buffered and unbuffered flavors: ch := conc.NewChan // buffered, capacity 2 defer ch.Free() // Producer on its own thread. prod := producer{ch: &ch, n: 5} thr := conc.Go(produce, &prod) defer thr.Wait() // Consume until the channel is closed and drained. var v int for ch.Recv(&v) { fmt.Printf("received %d\n", v) } Show the translated C code // conc_NewChan, conc_Chan_Recv, and friends are generic macros: // the element type (so_int here) is passed as the first argument. conc_Chan ch = conc_NewChan(so_int, mem_System, 2); // buffered, capacity 2 // Producer on its own thread. producer prod = (producer){.ch = &ch, .n = 5}; conc_Thread thr = conc_Go(produce, &prod); // Consume until the channel is closed and drained. so_int v = 0; for (; conc_Chan_Recv(so_int, &ch, &v);) { fmt_Printf("received %d\n", v); } conc_Thread_Wait(thr); conc_Chan_Free(so_int, &ch); Chan[T] is a thin generic shell over one of two engines, picked at creation time: Buffered (n > 0) is a mutex-guarded ring buffer with notEmpty and notFull condition variables β€” like the Pool queue. Senders block when it's full, receivers block when it's empty. type Buffer struct { alloc mem.Allocator mu sync.Mutex notEmpty sync.Cond // signaled when an item becomes available notFull sync.Cond // signaled when a slot frees buf mem.Array // ring buffer closed bool // true after Close } // Send copies v into the ring, blocking while it is full. func (ch *Buffer) Send(v any) { ch.mu.Lock() for ch.bfull() { ch.notFull.Wait() // back-pressure until a slot frees } ch.bpush(v) ch.notEmpty.Signal() // wake one waiting receiver ch.mu.Unlock() } Show the translated C code typedef struct conc_Buffer { mem_Allocator alloc; sync_Mutex mu; sync_Cond notEmpty; // signaled when an item becomes available sync_Cond notFull; // signaled when a slot frees mem_Array buf; // ring buffer bool closed; // true after Close } conc_Buffer; // Send copies v into the ring, blocking while it is full. void conc_Buffer_Send(conc_Buffer* ch, void* v) { sync_Mutex_Lock(&ch->mu); for (; conc_Buffer_bfull(ch);) { sync_Cond_Wait(&ch->notFull); // back-pressure until a slot frees } conc_Buffer_bpush(ch, v); sync_Cond_Signal(&ch->notEmpty); // wake one waiting receiver sync_Mutex_Unlock(&ch->mu); } The full implementation also checks for closed, but I left it out for brevity. Recv is the mirror method: block while empty, pop the next value, signal notFull to wake a sender. It also handles the closed channel, returning false once the buffer is closed and drained. The rest is this lock-wait- signal core. Buffer source code Unbuffered (n == 0) is a rendezvous: each send blocks until a receiver takes the value, copying vsize bytes directly from the sender's stack to the receiver's destination without using an intermediate buffer. type Rendezvous struct { alloc mem.Allocator vsize int // size in bytes of a handed-off value mu sync.Mutex cond sync.Cond // broadcast on every slot state change src any // the sender's published value (valid while full) full bool // a value is published and not yet freed claimed bool // the published value has been taken by a receiver closed bool // true after Close } // Send publishes v and waits for a receiver to take it. func (ch *Rendezvous) Send(v any) { ch.mu.Lock() for ch.full { ch.cond.Wait() // wait for the previous hand-off to finish } ch.src, ch.full, ch.claimed = v, true, false // publish ch.cond.Broadcast() // wakeup #1: wake a receiver for !ch.claimed { ch.cond.Wait() // wait until the value is taken } ch.src, ch.full = nil, false // free the slot ch.cond.Broadcast() ch.mu.Unlock() } Show the translated C code typedef struct conc_Rendezvous { mem_Allocator alloc; so_int vsize; // size in bytes of a handed-off value sync_Mutex mu; sync_Cond cond; // broadcast on every slot state change void* src; // the sender's published value (valid while full) bool full; // a value is published and not yet freed bool claimed; // the published value has been taken by a receiver bool closed; // true after Close } conc_Rendezvous; // Send publishes v and waits for a receiver to take it. void conc_Rendezvous_Send(conc_Rendezvous* ch, void* v) { sync_Mutex_Lock(&ch->mu); for (; ch->full;) { sync_Cond_Wait(&ch->cond); // wait for the previous hand-off to finish } ch->src = v; // publish ch->full = true; ch->claimed = false; sync_Cond_Broadcast(&ch->cond); // wakeup #1: wake a receiver for (; !ch->claimed;) { sync_Cond_Wait(&ch->cond); // wait until the value is taken } ch->full = false; // free the slot ch->src = NULL; sync_Cond_Broadcast(&ch->cond); sync_Mutex_Unlock(&ch->mu); } Recv is the other half: it waits for a published, unclaimed value, copies vsize bytes straight from the sender's stack into dst (no intermediate buffer), marks it as claimed, and broadcasts to wake the sender back, creating wakeup #2. One hand-off, two wakeups. Copying directly from the sender's stack is safe because of that second wakeup. src is a pointer to v, which lives on the sender's stack. While the receiver is reading it, the sender is parked in for !ch.claimed { ch.cond.Wait() }, so its stack frame stays alive. The sender only returns (and reclaims that memory) after the receiver sets claimed and wakes it up. There's no need to copy into a shared buffer because the source is guaranteed to outlive the read. Rendezvous source code As you can see, the API is pretty similar to Go. Now let's look at the numbers. Performance

      Here's the main tradeoff: pthread-based concurrency primitives are fast when no one has to block, but they get slow when someone does. And it's always for the same reason.

      Go schedules goroutines in userspace. When one goroutine blocks on a channel and another wakes it up, the runtime moves them between its own queues β€” no kernel involved. POSIX threads, on the other hand, don't provide a userland scheduler. When a thread blocks on a condition variable, it parks in the kernel, and waking it up requires a syscall. Every hand-off between threads that actually parks pays the cost of a syscall on both ends.

      You can clearly see the difference in the mutex benchmarks. With 8 competing threads, it all comes down to whether the waiting threads have to park or not:

      Mutex benchmark | Go | So | Winner
      ---|---|---|---
      Uncontended, 1 thread | 14ns | 9ns | So - 1.6x
      Contended spin, 8 threads | 75ns | 27ns | So - 2.8x
      Contended work, 8 threads | 1.1Β΅s | 2.0Β΅s | Go - 1.8x

      Each number is the average time for a single Lock/Unlock pair. The uncontended benchmark runs on one thread, while the contended benchmarks have multiple threads fighting over the same mutex.

      Notice that So actually wins the first two benchmarks, and for good reason. So's Lock is a plain pthread_mutex_lock call with nothing extra, while Go's sync.Mutex adds more overhead β€” like starvation-mode tracking and a runtime that stays involved because a goroutine can be preempted in the middle of a critical section.

      When nobody parks, that overhead is the main cost, and the thinner wrapper is closer to the hardware. With an empty critical section (the spin benchmark), a waiting thread grabs the lock while still spinning and almost never parks β€” So wins by 2.8x. The uncontended benchmark (a single thread, no contention) shows the same thing: less code between the call and the lock, so 9ns versus 14ns.

      The picture flips the moment threads have to park. Give the critical section about a microsecond of real work (the work benchmark) and waiters exhaust their spin budget and park. Now every hand-off costs a wakeup syscall, and So drops to half of Go's throughput. The work is identical in both cases β€” the difference comes from the parking cost.

      Condition variables demonstrate this clearly because they always park:

      Cond benchmark | Go | So | Winner
      ---|---|---|---
      1 waiter | 150ns | 1.5Β΅s | Go - 10x
      8 waiters | 2.0Β΅s | 14Β΅s | Go - 7.0x
      32 waiters | 9.0Β΅s | 60Β΅s | Go - 6.7x

      Each number is the cost of one rendezvous round: a single broadcast that wakes every waiter and hands control back, with N waiters plus one broadcaster.

      Pthread-based condition variable is consistently 7-10 times slower. There's no trick to close this gap β€” it's just the cost of waking up a real OS thread instead of a goroutine.

      Channels have the same issue because they're built using mutexes and condition variables:

      Chan benchmark | Go | So | Winner
      ---|---|---|---
      Uncontended, 1 thread | 24ns | 21ns | So - 1.1x
      Unbuffered, 2 threads | 130ns | 3.0Β΅s | Go - 23x
      Buffered (10), 2 threads | 44ns | 400ns | Go - 9.1x
      Buffered (100), 2 threads | 33ns | 70ns | Go - 2.1x

      Each number is the cost of moving one value through the channel (send plus its matching receive). The number in parentheses is the buffer capacity.

      The uncontended case fills and drains a buffer from a single thread, so nothing ever blocks β€” it's just a lock plus a copy, which gives So a slight advantage. But the moment a producer and consumer actually start handing off work, So has to wake up a thread for every transfer that gets parked. It's worst for the unbuffered channel, where every value is a rendezvous with two wakeups: 23x slower. A larger buffer helps a lot β€” with room for 100 items, most sends go through without waking anyone, and the gap narrows to about 2x.

      The consequence is that the larger your tasks are, the better pthread-based concurrency works. If you use a channel for fine-grained, value-at-a-time streaming between threads, performance will suffer. But if you use a channel to pass whole work items to a pool, where each item takes tens of microseconds to process, the wakeup cost becomes negligible. The pool benchmarks on realistic workloads confirms this:

      Pool benchmark | Go | So | Winner
      ---|---|---|---
      1000 CPU tasks (~40Β΅s each) | 7ms | 8ms | Go - 1.1x
      64 IO tasks (1ms block each) | 9ms | 10ms | Go - 1.1x

      Each number is the wall-clock time for 8 workers to process the whole batch.

      Here, So is within 1.1x of Go. The per-task dispatch cost is still present, but it's spread out over real work, and the performance penalty is pretty small.

      Benchmarking

      All benchmarks were run on an Apple M1 CPU running macOS. The C code was compiled with Clang 16 using these CFLAGS and mimalloc as the system allocator:

      -Ofast -march=native -flto -funroll-loops -DNDEBUG
      

      The results shown are the medians from several benchmark runs. Each benchmark ran many iterations, following the same logic as Go's own benchmarking.

      The Go benchmarks used Go 1.26 and go test -bench=..

      Source code for both So's and Go's benchmarks: conc β€’ sync

      Here's a summary of the strengths and weaknesses of the pthread-based approach:

      • βž• Coarse-grained pooled workloads are within about 10% of Go's performance.
      • βž• Uncontended locks and spin-friendly critical sections perform quite well.
      • βž• Atomic operations are as fast as in Go.
      • βž• The implementation is 100x simpler.
      • βž– Anything that needs to park and wake an OS thread is much slower than Go's userspace scheduler.
      • βž– The pool can't handle thousands of blocked waiters like goroutines can.

      If you're looking for "thousands of cheap goroutines", the pthread-based approach will let you down. But if you're fine with "a few worker threads handling lots of tasks", it holds up well.

      Design decisions

      Three decisions influenced the way I implemented concurrency in Solod.

      Pthreads, not fibers. I know there are coroutine/fiber libraries for C that avoid the kernel wakeup cost β€” single-threaded ones like neco, and multi-threaded ones like libfiber. A userspace scheduler is exactly what would help to match Go in the benchmarks above.

      I decided not to use one. I wanted something dead simple β€” an approach I could explain in a paragraph, using tools every C programmer already knows. The trade-off is that you lose some performance with fine-grained blocking, but in many real-world situations, pthreads work fine if you use a worker pool. For me, keeping things simple is more important than saving a few microseconds during task hand-offs. For now, at least.

      Standard library, not language. Go bakes goroutines, channels, and select right into the language. I decided to keep everything in the stdlib for two reasons.

      βž€ It follows So's "no hidden allocations" rule. In Go, go f() quietly allocates a goroutine stack, and make(chan T, n) allocates a buffer. In So, all allocations are explicit: you pass an allocator to NewChan and NewPool, and you always know exactly where the memory comes from β€” whether it's the system allocator, an arena, or something else.

      ➁ A library is more flexible. Since a pool is a regular value, you can have as many as you need, each sized for its specific purpose. In a multi-stage pipeline where each stage needs a different capacity, you can start one pool per stage, each with its own NumThreads and QueueSize, instead of being given a single global scheduler. The language stays simple, and the flexibility is in code you can easily read.

      Timeouts, not select. Go's select waits on several channel operations at once and proceeds with whichever is ready first. Implementing it would require a lot of work β€” a thread has to register interest on multiple channels, block once, and then wake up when any of them is ready β€” so I left it out. Instead, Chan offers SendTimeout and RecvTimeout, which cover two common uses of select with a single channel:

      • "Do this, but give up after a while" (Go's case <-time.After(...) idiom).
      • "Do this only if it won't block" (Go's non-blocking default branch).

      What's missing is the ability to block on multiple channels at once and continue with whichever one is ready first, as well as the option to mix sends and receives in the same selection.

      Wrapping up

      How close can you get to Go's concurrency using only pthreads? Close enough to be useful, but not enough to really match Go. You can wrap real OS threads with familiar APIs β€” mutexes, condition variables, pools, channels β€” and the code will look and act a lot like Go, at least until a thread needs to block. But there's no scheduler underneath, so when a thread blocks, it's an actual thread waiting in the kernel, not a goroutine that's paused for free. That's the main limitation of this approach.

      What you get in return is brutal simplicity. Every primitive is a thin wrapper with no runtime hiding behind it, so the performance is exactly what the OS gives you: fast atomics, fast uncontended locks, and pooled throughput within ~10% of Go on coarse-grained work. But as soon as you switch to fine-grained, one-value-at-a-time hand-offs, the cost of kernel wakeups becomes the main factor, and you'll notice the slowdown.

      If you think the pthread approach might work for you, I invite you to try Solod. It includes the sync and conc packages, along with many others ported from Go's standard library.

    4. πŸ”— Barre/ZeroFS v2.0.9 release

      What's Changed

      • Make HA segment materialization atomic by @Barre in #526
      • Replace extent publication barrier with RwLock by @Barre in #527

      Full Changelog : v2.0.8...v2.0.9

    5. πŸ”— benji.dog rss

      O: "Burj Khalifa is the tallest building, right?" Me: "yes" O: "So what's the shortest building?" Me: 😢

    6. πŸ”— anthropics/claude-code v2.1.206 release

      What's changed

      • Added directory path suggestions to /cd, matching /add-dir behavior
      • Added a /doctor check that proposes trimming checked-in CLAUDE.md files by cutting content Claude could derive from the codebase
      • /commit-push-pr now auto-allows git push to the repo's configured push remote (remote.pushDefault, or the sole remote when only one is configured) in addition to origin
      • Gateway: /login now supports Anthropic-operated public gateway endpoints
      • EnterWorktree now asks for confirmation before entering a git worktree outside the project's .claude/worktrees/ directory
      • Background agents now upgrade to a new version in the background right after a Claude Code update, instead of paying a slow stale-session upgrade when you attach
      • Fixed an expired login failing every model with a misleading "There's an issue with the selected model" error instead of prompting to run /login
      • Fixed claude --resume and --continue not responding to keyboard input on startup
      • Fixed MCP servers configured via --mcp-config or .mcp.json ignoring a per-server request_timeout_ms, which caused long-running MCP tool calls to time out at the 60s default in fresh sessions
      • Fixed CLAUDE_CODE_EXTRA_BODY being silently ignored by claude agents / --bg background workers; the shell-exported override now follows the dispatching session
      • Fixed OAuth MCP servers requiring manual re-authentication after a single failed token refresh
      • Fixed --permission-prompt-tool pointing at an MCP server crashing with "MCP tool not found" on cold start before the server finishes connecting
      • Fixed /model picker rows printing a price for a different model than the row named, and stopped quoting first-party list prices on providers that don't bill them
      • Fixed server-provided model rows being misplaced in the /model picker when an entitlement or allowlist restriction drops the row they were positioned against
      • Fixed desktop sessions getting stuck showing "running" after a slash command was sent mid-turn
      • Fixed keyboard input being ignored in the agents view when a setup prompt appeared before a bare claude --resume on Windows
      • Fixed claude rm leaving the removed job in the daemon roster, causing the row to reappear in claude agents
      • Fixed /remote-control showing "Unknown command" when logged out β€” it now explains how to sign in
      • Fixed left arrow not stepping back out of a phase or agent in the workflow detail view
      • Fixed /status listing the same broken-install warning twice
      • Fixed false "disused plugin" tips and skewed disuse telemetry for LSP plugins
      • Fixed /doctor's update check to compare Homebrew installs against their cask's channel instead of the settings channel
      • Fixed the fullscreen jump-to-bottom pill suggesting Ctrl+End on macOS, not showing rebound chords, and wrapping over the transcript
      • Bedrock: fixed a multi-minute startup hang when using an awsCredentialExport helper on networks with restricted egress
      • Improved /code-review findings quality on claude-opus-4-8 across all effort levels
      • Improved agents view: status column now uses full terminal width instead of truncating at 64 characters
      • Changed agents view: Ctrl+X now permanently removes a completed session, and sessions no longer render twice; deleted background jobs stay deleted
    7. πŸ”— Barre/ZeroFS v2.0.8 release

      What's Changed

      • Add deterministic simulation testing for the extent-store data plane by @Barre in #519
      • Fuzz and harden the 9P and NBD protocol decoders by @Barre in #521
      • Fail closed on segment materialization HEAD errors by @Barre in #522
      • Backpressure extent writes before growing an overdue open segment by @Barre in #520

      Full Changelog : v2.0.7...v2.0.8

    8. πŸ”— New Music Releases Bring Me the Horizon - Count Your Blessings | Repented rss

      Bring Me the Horizon - a new release is available:

      • 2026-07-10: Count Your Blessings | Repented (Album)

      Amazon: Canada | Deutschland | France | United Kingdom | United States

      Visit muspy for more information.

    9. πŸ”— New Music Releases If These Trees Could Talk - The Hidden Hand rss

      If These Trees Could Talk - a new release is available:

      • 2026-07-10: The Hidden Hand (Album)

      Amazon: Canada | Deutschland | France | United Kingdom | United States

      Visit muspy for more information.

  3. July 09, 2026
    1. πŸ”— IDA Plugin Updates IDA Plugin Updates on 2026-07-09 rss

      IDA Plugin Updates on 2026-07-09

      Activity:

      • ghidra
        • c7057c19: GP-0: Adding Markdown support to Doclets
      • ida-domain
        • 8e26b257: Add quotes to path parameters (#93) (#95)
        • d0812acd: Downgrade test guards to 9.4 (#96)
      • ida-hcli
        • 814026b5: AI-assisted: fix: ida open, support ida:/// URLs (d…
      • playlist
      • project
        • 75131be4: added cfunctions from ghidra
      • rikugan
        • 26e35fd6: chore(release): bump version to 1.10.1
        • 75a9066c: fix(ui): clear stale height pin in _HeightCachedLabel
        • 3961b78c: fix(ui): remove double-spacing between paragraphs
        • db63d535: docs(readme): bump version badges to 1.10.0
        • 3b6bd644: fix(ui): migrate ExecutePythonWidget to bind_theme
        • 361c29e3: Updating README and fixing UI setting
        • eacf6a3a: Merge remote-tracking branch 'EliteClassRoom/master'
        • 5d8f986a: chore(release): bump version to 1.10.0
        • bf1621a4: Merge branch 'feat/execute-python-unified-widget'
        • 83884131: fix(ui): hide code section + result frame when collapsed to remove gap
        • 9c447004: fix(ui): hide Result label when collapsed
    2. πŸ”— Simon Willison The new GPT-5.6 family: Luna, Terra, Sol rss

      OpenAI's latest flagship model hit general availability this morning, and comes in three sizes: Luna, Terra, and Sol (from smallest to largest).

      The new models are priced per 1M input/output tokens as Luna $1/$6, Terra $2.50/$15, Sol $5/$30. For comparison, the Claude Opus series are $5/$25 and the Claude Fable 5 is $10/$50, but price-per-million tokens doesn't tell us much now that the number of reasoning tokens can differ so much between models for the same task.

      All three models have a February 16th 2026 knowledge cutoff, a million token context window, and 128,000 maximum output tokens.

      OpenAI's biggest benchmark claim concerns long-running agentic performance, with one benchmark showing all three models outperforming Claude Fable 5:

      We trained GPT-5.6 to get more useful work from every token. On Agents’ Last Exam, an evaluation of long-running professional workflows across 55 fields, GPT-5.6 Sol sets a new high of 53.6, eclipsing Claude Fable 5 (adaptive reasoning) by 13.1 points. Even at medium reasoning, it beats Fable 5 by 11.4 points at roughly one-quarter the estimated cost. That efficiency extends to smaller models, which are essential to making intelligence more abundant and affordable: GPT-5.6 Terra and GPT-5.6 Luna outperform Fable 5 at around one-sixteenth the cost.

      Amusingly, one self-reported benchmark that Fable 5 crushed the GPT-5.6 family on was SWE-Bench Pro, where Fable 5 got 80% compared to GPT-5.6 Sol getting 64.6%. This may help explain why OpenAI chose to publish this article yesterday specifically calling out SWE-Bench Pro for problems they found while auditing that benchmark:

      In light of these results, we estimate that ~30% of SWE-bench Pro tasks are broken, and advise that model developers carefully examine results

      I've had some early access to GPT-5.6 Sol - it's definitely very competent, though so far it hasn't struck me as better than Fable at the kind of complex coding tasks I've been using with Anthropic's model.

      As usual, the model guidance for using GPT-5.6 has the most interesting details. There are a bunch of new API features that I need to explore (and probably add support for in LLM), including:

      • Programmatic Tool Calling allows the models to "compose and run JavaScript that orchestrates tool calls" - which sounds to me like it could help bridge the gap between MCPs and full terminal sessions that can compose CLI utilities in useful ways. Also reminiscent of the dynamic filtering mechanism Anthropic added to their web search tool, which allows code execution against web results as part of a single model turn.
      • Multi-agent lets the model "spin up subagents for parallel, focused work" - the sub-agent pattern now baked into the core API.
      • Prompt cache breakpoints brings the Claude model of prompt caching to OpenAI, letting you be explicit about where the cache breakpoints are rather than relying on the API to detect them automatically. Personally I much prefer automatic detection (still supported by OpenAI), but presumably there are optimization cost savings to be had here if you put the work in.
      • You can now set detail: original on image requests to avoid resizing the image at all before it is processed.

      Here's a full page with 18 different pelicans - for reasoning efforts none, low, medium, high, xhigh, and max across the three different models. It also lists their token and calculated costs - the least expensive was gpt-5.6-luna at effort none for 0.71 cents, the most expensive was gpt-5.6-sol at max reasoning level for 48.55 cents.

      A grid of nine pelicans riding bicycles, of varying quality

      In further pelican news, if you jump to 17:50 in their livestream from this morning you'll see OpenAI's own demo of 3D pelicans riding a tricycle, a bicycle, a pony, and another pelican!

      Frame from a livestream showing a 3D model of a pelican riding another pelican

      You are only seeing the long-form articles from my blog. Subscribe to /atom/everything/ to get all of my posts, or take a look at my other subscription options.

    3. πŸ”— The Pragmatic Engineer The Pulse: Interesting AI coding stats from Cursor rss

      Hi, this is Gergely with a bonus, free issue of the Pragmatic Engineer Newsletter. In every issue, I cover Big Tech and startups through the lens of senior engineers and engineering leaders. Today, we cover one out of four topics _a past _The Pulse issue__ . Full subscribers received the article below five weeks ago. If you 've been forwarded this email, you can subscribe here .

      Cursor has just released a new report based on two years of its aggregated usage data, and there are some interesting findings:

      Power users generate 10x as many lines of code vs the median

      alt Source:Cursor

      The median dev using Cursor (the p50) generates about 700 lines of code per week with it, while for the 90th percentile, it's closer to 9,000 lines.

      Top 1% of users create incredible volume of code

      The p99 data is pretty stunning:

      altThe top 1% of Cursor users (p99) vs the top 10% (p90)

      The top 1% of users generate around 30-40K lines of code per week! That's the equivalent of what ~45 "median" devs generate in the same period.

      It's worth asking how these top 1% of users are different. Are they writing a lot more greenfield code, do they have a bias for not using libraries, are they tokenmaxxing to get to the top of leaderboards? Do they generate 45x as many bugs, and importantly: are they adding a lot of business value with the software they ship?

      Cursor consumes 10x more input tokens than it generates in output tokens

      This is surprising: 90% of Cursor's token usage is input tokens! This means that most of the tokens used are for reading the existing codebase and documentation. Outputting of code is a minority usage:

      altInput tokens (Cursor reading the codebase) is the bulk of token usage

      In some ways, this usage makes sense: as devs, we always spent far more time on reading the code, compared to lines of code we typed out. The "10:1 read- to-write" ratio is a classic. Here's Robert. C. Martin (aka "uncle Bob") sharing this observation in 2008, in his book, Clean Code:

      "Indeed, the ratio of time spent reading versus writing is well over 10 to 1. We are constantly reading old code as part of the effort to write new code… [Therefore] making it easy to read, makes it easier to write."

      I find it amusing that we're now seeing this 10:1 read / write ratio for token usage with AI agents!

      Input tokens become the main AI token cost

      Input tokens are priced at a fraction of output tokens: for example, Opus 4.7 charges 5x more for output tokens than for input tokens ($5 per 1 million input tokens and $25 per 1 million output tokens). Still, thanks to input tokens dominating token usage, Cursor is seeing input tokens account for closer to 70% of the cost of AI coding agents:

      altInput tokens dominate Cursor costs

      Without caching context, token cost would be 10x higher

      Cursor does smart caching of context, to avoid re-generating old context with more new input tokens. When taking cache usage into account, Cursor only spends 0.6% of tokens on output tokens. The remaining 99% is split between cache read (90%), cache write (2.5%), and input tokens (7%):

      altOutput tokens are only 0.6% of token usage when considering cache reads & writes

      I wonder if context reuse and caching will be a key AI efficiency component in the future? AI tokens are expensive to generate, so any form of reuse will make a lot of sense, especially in workflows like coding where a lot of existing context is reused.

      Of course, Cursor sharing this detail also makes sense, as they remind everyone that building an efficient AI agent harness is far from trivial. Indeed, if you roll your own agent harness, you also need to put an efficient caching layer in place to match the efficiency of tools like Cursor.

      Opus is the most expensive model & could hurt Anthropic

      At the time of publishing, Opus 4.7 was still considered the most capable coding model. However, it's also very expensive, and Cursor's own data shows it's close to 10x more expensive than its own Composer 2.5 model:

      altOpus 4.7 is twice as expensive as GPT-5.5 & nearly 10x more than Composer 2.5

      It's significant that Cursor compares the cost of a single agent request; it's not a direct token-to-token comparison. And it's worth noting this benchmark is being shared by Cursor, which has an incentive for its Composer model to appear the lowest-cost.

      Still, assuming you can get similar-enough results with a 10x cheaper model, it is a saving that's hard to ignore, especially for mid-sized and above companies. I would not be surprised if more tech companies find ways for devs to use less capable - but cheaper - models for less critical work.

      More expensive models result in higher acceptance rates

      An interesting metric Cursor shares is cost-per-line-added, per model:

      alt

      This metric is a more realistic cost because it correlates to output: "smart" models that are expensive, but which produce code that is frequently accepted, are penalized by the cost-per-agent-request metric, but they're not here.

      Indeed, Opus 4.7 has the same cost-per-line-accepted as GPT 5.5 at half the cost per agent request. In this comparison, Cursor's Composer model is "only" 5x as efficient.

      Missing from both lists are Google's Gemini models, a strange omission by Cursor. I reached out to Cursor and they told me that Gemini was left out simply because they see very little usage of this model on their platform, similar to the sparsely used Grok model.

      Almost half of AI changes accepted without manual review by devs

      I've left the most interesting part of this report to last: in just a month, among devs using Cursor, it has gone from 10% who let AI agents create commits without a manual step, to around 40% of devs who no longer personally check the code:

      alt

      The jump correlates with Opus 4.7 and GPT-5.5 being released, and around the time when many devs seem to have concluded that writing code by hand is dying after experiencing this generation of models' capability at generating code.

      Check out the full report from Cursor for more details. Thanks to the team for releasing this data!


      Read the full issue of The Pulse this excerpt is from, or check out the latest The Pulse from today. Today's issue covers:

      • Bun's Rust rewrite with Fable: what can we learn?
      • Anthropic's Fable, OpenAI's GPT-5.6 Sol, Cursor's Grok 4.5, Meta's Muse
      • North Korean hackers keep trying to infiltrate full-remote companies
      • Industry Pulse: Meta's key logging exposed sensitive data, massive cuts at Xbox, Meta could not buy enough AI capacity from Google, Qualcomm acquires Modular, and memory price hikes hit Apple products.
    4. πŸ”— pydantic/pydantic-ai-harness v0.6.0 (2027-07-09) release

      What's Changed

      • Bump vcrpy to 8.2.1 to fix YAML deserialization RCE by @adtyavrdhn in #300
      • feat(subagents): configurable delegate-tool retries by @dsfaccini in #324
      • feat(subagents): contain unexpected sub-agent crashes as bounded retries by @dsfaccini in #326
      • feat(experimental): serve a Pydantic AI agent over ACP by @adtyavrdhn in #274
      • feat(experimental): Dynamic Workflows Capability by @adtyavrdhn in #273

      Full Changelog : v0.5.0...v0.6.0

    5. πŸ”— @malcat@infosec.exchange In the upcoming 0.9.15 release, Malcat will embed its own 100% native mastodon

      In the upcoming 0.9.15 release, Malcat will embed its own 100% native #capa engine. So you get:
      - x10 .. up to x100 scan speedup
      - command line tool (using headless malcat lib)
      - embedded capa rule editor
      - additional architectures: arm, mips and even ... python:

    6. πŸ”— navidrome/navidrome v0.63.1 release

      Changelog

      Bug fixes

      • 052f10f: fix(build): prevent 32-bit startup crash (segfault/SIGILL) in downloads binaries (#5739) (@deluan)
      • f48943c: fix(plugins): discard buffered scrobbles when a plugin is removed (#5737) (@deluan)
      • 4652b46: fix(plugins): populate username for buffered plugin scrobbles (#5736) (@deluan)
      • 42d4363: fix(service): rewrite systemd service template for kardianos/service v1.3.0 (#5743) (@deluan)

      Full Changelog : v0.63.0...v0.63.1

      Helping out

      This release is only possible thanks to the support of some awesome people!

      Want to be one of them?
      You can sponsor, pay me a Ko- fi, or contribute with code.

      Where to go next?

    7. πŸ”— Barre/ZeroFS v2.0.7 release

      Segment reclaim & compaction correctness

      • 169d1d4 : Compare the full FrameLoc in the compaction repoint CAS so a rewrite into the same source segment is not reverted to the stale frame.
      • b9d0dd8 : Read the segment-reclaim segcount scan at the durable level so a segment is never deleted while its death is still an unflushed in-memory debit.
      • 7e9e4e2 : Prove reclaim deletes from the durable view under the WAL-off production config.
      • eb4f9e7 : Check the durable view too in the segment directory-verify so an unflushed overwrite cannot mask a durably referenced frame from the delete backstop.
      • 9a3827c : Keep compaction's gather compressed end to end (verify and AAD-rebind only), cap the round in stored bytes plus per-frame overhead, and fan the batch AEAD out on rayon in both directions.

      HA / replication correctness

      • dcb1e6c : Key the cross-term tail clear on the tail's own epoch, not the heartbeat-advanced fence, so a restarted leader's stale tail cannot replay over the new term's fsync-acked writes.
      • cfae108 : Validate takeover replay against a per-batch durable provenance stamp and gate boot on a latest-leader record so neither a stale tail nor an election from silence can regress acked state.
      • b3b6028 : Raise the replication decode limit above tonic's 4 MiB default.

      Robustness fixes

      • f2d5a6b : Forward mid-scan iterator errors into the Db::scan stream instead of swallowing them as a clean end-of-range.
      • 5b66e77 : Reject a write or trim whose offset + length overflows u64 as EINVAL instead of wrapping into a request-task panic or a stray unreachable extent.

      Refactors & housekeeping

      • 2bdf0e0 : Fix clippy warning.
      • 0cbf4b3 : Split extent.rs into an extent/ module: read, write, select, reclaim, compact.
      • f67f347 : Split fs/mod.rs into boot, handle, and per-op ops/ files with their tests.

      Full Changelog : v2.0.6...v2.0.7

    8. πŸ”— Rust Blog Announcing Rust 1.97.0 rss

      The Rust team is happy to announce a new version of Rust, 1.97.0. Rust is a programming language empowering everyone to build reliable and efficient software.

      If you have a previous version of Rust installed via rustup, you can get 1.97.0 with:

      $ rustup update stable
      

      If you don't have it already, you can get rustup from the appropriate page on our website, and check out the detailed release notes for 1.97.0.

      If you'd like to help us out by testing future releases, you might consider updating locally to use the beta channel (rustup default beta) or the nightly channel (rustup default nightly). Please report any bugs you might come across!

      What's in 1.97.0 stable

      Symbol mangling v0 enabled by default

      When Rust is compiled into object files and binaries, each item (functions, statics, etc) must have a globally unique "symbol" identifying it. To avoid conflicts when linking together different Rust programs, Rust mangles the original name of items to include additional context such as the module path, defining crate, generics, and more. Historically, this mangling was based on the Itanium ABI, also (sometimes) used by C++.

      The new mangling scheme resolves a number of drawbacks from the previous one:

      • Generic parameter instantiations preserve their values, rather than being tracked solely behind a hash
      • Inconsistencies: not all parts used the Itanium ABI, meaning that custom demangling was still necessary

      Since Rust 1.59, the compiler has supported opting into a Rust-specific mangling scheme via -Csymbol-mangling-version=v0. Since November 2025, this scheme has been enabled by default on nightly, and 1.97 is now enabling it on stable Rust. The legacy mangling scheme can only be enabled on nightly, and the current plan is to fully remove it.

      See the previous blog post for more details.

      Cargo support for denying warnings

      It's common practice to deny warnings in CI. Historically, doing so is typically done through RUSTFLAGS=-Dwarnings. With Rust 1.97, Cargo controls how warnings interact with build success: either silencing them (via allow level), rendering without failing (default, warn), or denying them (via deny).

      As a result of Cargo configuration determining the behavior, using this feature doesn't invalidate the underlying build cache, meaning that it's easy to temporarily opt-in. For example, if warnings are adding unwanted noise while working through fixing errors after a refactor, you can run CARGO_BUILD_WARNINGS=allow cargo check, temporarily silencing them.

      In CI, jobs can instead set CARGO_BUILD_WARNINGS=deny to deny warnings. This can be combined with --keep-going to collect all errors and warnings rather than stopping on the first failing package.

      See the documentation for more details.

      Linker output no longer hidden by default

      rustc invokes a linker on behalf of users. Historically, rustc has silenced linker output by default if the link completes successfully. This can mask real problems, though, so in Rust 1.97 we are enabling linker messages by default. These are emitted as a warning lint, for example:

      warning: linker stderr: ignoring deprecated linker optimization setting '1'
        |
        = note: `#[warn(linker_messages)]` on by default
      

      Common linker messages that have been diagnosed as false positives or intentional behavior are filtered out by rustc. Several defects have already been fixed as a result of no longer hiding this output on nightly.

      Note that currently, linker_messages is a special lint that is not affected by the warnings lint group. This is intentional as rustc generally doesn't control linker output as precisely, and it's not uncommon for output to only appear on some platforms. If you are seeing what you think is a false positive output from the linker, please file an issue.

      To silence the warning in the mean time, you can configure the lint level to allow. This can be done through Cargo.toml by adding a lints section like this:

      [lints.rust]
      linker_messages = "allow"
      

      Stabilized APIs

      These previously stable APIs are now stable in const contexts:

      Other changes

      Check out everything that changed in Rust, Cargo, and Clippy.

      Contributors to 1.97.0

      Many people came together to create Rust 1.97.0. We couldn't have done it without all of you. Thanks!

    9. πŸ”— Console.dev newsletter Davit rss

      Description: Native macOS Container GUI.

      What we like: Manage Apple Containers via the UI. Open a shell inside any container. Supports volumes, images, networks. Built-in file browser. View container stats and inspect container details. Native macOS app, not Electron.

      What we dislike: Not a Docker replacement - it’s Apple’s own implementation. Try OrbStack if you need that (and other things like VMs).

    10. πŸ”— Console.dev newsletter ZeroFS rss

      Description: Log-structured filesystem for S3.

      What we like: Makes S3-compatible buckets appear as POSIX filesystems or raw block devices. Supports NFS, 9P, NBD. Use ZFS to mirror across regions. Segments are immutable, compressed, encrypted. Local caching. Optional web dashboard and file manager.

      What we dislike: AGPL licensed by default, alternative available on a commercial basis.

    11. πŸ”— Ampcode News The Dial rss

      Amp's agent modes are now a dial: low, medium, high, ultra. They replace smart, deep, rush, and large.

      Amp's mode dial in the CLI showing low, medium, high, and ultra

      The old modes were models in disguise: each name hid a model, a prompt, a reasoning effort β€” and to pick one, you had to know what that model was like this month. That world is gone. The models converged, open-weight models got seriously good, and the only question left is capability against cost.

      The dial asks one question: how hard is this task?

      Missing in either direction costs you. Undershoot and the model churns: wrong fix, re-prompt, wrong fix again. You pay three times for a result you could have had once. Overshoot and you're using Fable to fix a typo. Set it right and you pay for exactly the intelligence the task needs.

      • ultra β€” The outcome is clear, but the path is full of unknowns. Migrations, architecture, changes that span many files, systems, and decisions the model has to discover as it goes.
      • high β€” You know where the change goes, but getting it right is hard: cross-cutting changes, concurrency, bugs where a subtle miss is expensive. You get diffs closer to reviewer-ready than medium gets you β€” but plan on one round of feedback before merging, and about twice the wait.
      • medium β€” You know roughly what you want. This should be your default. It handles messy, multi-part tasks, fuzzy requirements, the steps you didn't spell out. Strong enough for most work, fast enough to steer.
      • low β€” You know exactly what you want. Bug fixes, tests, refactors, features you can describe precisely. There is less to figure out for the model, so low builds it.

      Turn the dial with Ctrl+S in the CLI, or with the mode picker in the web app.

      Amp's mode picker in the web app showing low, medium, high, and ultra

      Under the Hood

      We want you to know exactly what you're getting, so here's what backs each mode today. This wiring will change as models improve. The dial won't.

      • ultra: Claude Fable 5, with a system prompt written for it. GPT-5.6 Sol as the oracle.
      • high: GPT-5.6 Sol at xhigh reasoning effort. Claude Fable 5 as the oracle.
      • medium: GPT-5.6 Sol at medium reasoning effort. GPT-5.6 Sol at high effort as the oracle.
      • low: GLM-5.2, Z.ai's open-weight model, the strongest open model on agentic coding. GPT-5.6 Sol as the oracle. (Workspace admins can choose to use GPT-5.6 Terra low instead of GLM-5.2 here.)

      Reasoning effort is part of the tier now. No more cycling Opt+D through effort levels on top of picking a mode.

      Every mode has an oracle for second opinions. On the top tiers, it's the other frontier model: in high, GPT-5.6 Sol writes and Fable reviews. In ultra, Fable writes and GPT-5.6 Sol reviews.

      Migrating

      • smart, deep β†’ medium (same model and effort as deep). Turn up for hard problems.
      • rush β†’ low.
      • deep**3 -> ultra or high

      Want to Tune It Yourself?

      The dial removes knobs from the default experience, not from Amp. Plugins can register their own agent modes with your model, your prompt, and your tools, and they show up right next to the built-in ones.

      We used that same plugin API to package up the deprecated modes β€” exact system prompts, exact tool lists, same models and reasoning efforts. If you want smart, deep, rush, or large back, install them:

      amp plugins add --auto-update @amp/smart-classic
      amp plugins add --auto-update @amp/deep-classic
      amp plugins add --auto-update @amp/rush-classic
      amp plugins add --auto-update @amp/large-classic
      

      Then run plugins: reload (or restart the CLI) and they appear in the mode picker as Smart (classic), Deep (classic), Rush (classic), and Large (classic) β€” the original names stay reserved for the built-ins. --auto-update keeps them current when we update the plugins; drop it if you'd rather pin. The full list of installable modes is on ampcode.com/models.

      Start at medium. Turn it down when the task is clear. Turn it up when a miss costs more than the wait.

      We'll follow up with posts on each mode and numbers on what each one can handle.

  4. July 08, 2026
    1. πŸ”— IDA Plugin Updates IDA Plugin Updates on 2026-07-08 rss

      IDA Plugin Updates on 2026-07-08

      New Releases:

      Activity:

      • atelier
        • e98c4662: chore: bump landing submodule - footer reorganized, all 13 vs-compar…
        • 7ff16e86: docs: add vs-caveman and vs-rtk comparisons; expand README header nav…
        • 9357c0f9: docs: expose full benchmark suite + named-competitor comparisons
        • f3b89287: chore: bump to v0.2.7
        • 7c30a33e: chore: bump to v0.2.6
        • f5e2a0c2: Revise landing page copy and mockup for Atelier to emphasize savings …
        • d2254599: Move installer state under atelier home
      • ghidra
        • ee4fba70: Merge remote-tracking branch 'origin/GP-0_d-millar_test_fix'
        • 28f58b3e: GP-0: Javadoc fixes
        • 8f1fd58f: GP-0: tired of seeing this
        • de2b2180: Merge remote-tracking branch 'origin/patch'
        • f9316e1e: Merge remote-tracking branch
      • ida-multi-mcp
        • 9016453f: docs: update star history chart embed URL (#25)
        • 7b99f0c7: fix: real batched jTrans embedding + MPS device support (#23)
        • 58dfe7bc: feat: serve partial similar_functions() results during index builds (…
      • ida_rpc
      • plugin-ida
        • 7ace61d3: Merge pull request #155 from RevEngAI/feat-PRO-313
        • 3f650955: feat(PRO-313): analysis tags
        • 620a5bd7: Merge pull request #154 from RevEngAI/feat-PLU-311
        • 73ee01a7: fix: suppress error message - race between queued delivery and teardown
        • ce5a4614: feat(PLU-311): persist function jumps in chat history, render bug fix
        • 8aa03a2e: Merge pull request #153 from RevEngAI/chore/auto-bump-revengai
        • f253a28d: chore: bump revengai to 3.110.0
      • project
        • a1ac69c6: added ghidra.sh, demangle.py and CLI flag -ghidra
      • Spectra
        • 2000745d: Improve spawn_subagent UI; fix Popen pipes
        • a915630a: Load shell_auto_approve_limit from config
        • c44cf8fe: Display subagent events in shell REPL
        • 265adde9: Print notice when auto-approving safe shell commands
        • 14224c15: Make shell auto-approve limit configurable
        • acdd604c: Track shell approval state and handle input aborts
        • cb9493b5: Add safety checks and thread safety to shell commands
        • 2bfdd2af: Add SSH remote execution and file transfer tools
        • e0bb4348: Refine shell command safety patterns
        • 3cec041d: Document new interactive CLI features
        • 8d20b025: Add graceful Ctrl+C handling for agent interruption
        • 7812b44c: Print full shell command in approval messages
        • be9dd0ec: Show truncated shell command in approval messages
    2. πŸ”— anthropics/claude-code v2.1.205 release

      What's changed

      • Added an auto mode rule that blocks tampering with session transcript files
      • Fixed --json-schema silently producing unstructured output when the schema was invalid, and schemas using the format keyword being rejected
      • Fixed a message sent while Claude was working being silently lost when the turn ended at the --max-turns limit
      • Fixed Windows worktree removal deleting files outside the worktree when an NTFS junction or directory symlink existed inside it
      • Fixed background agents staying shown as "failed" or "completed" in the agent list after being resumed with SendMessage
      • Fixed background jobs flipping from "needs input" back to "working" in the agent list when the agent's turn contained no readable text
      • Fixed claude attach erroring when a background agent was mid-upgrade restart instead of waiting for it to come back
      • Fixed session-to-PR linking missing a PR created in a Bash call whose output exceeded the 30K inline limit
      • Fixed claude mcp add-from-claude-desktop getting stuck when a server name contains unsupported characters; invalid names are now reported and remaining servers still import
      • Fixed a plugin LSP server that fails to initialize preventing a valid LSP server from another plugin handling the same file extension
      • Fixed a Windows crash when the directory Claude was launched from is deleted, locked, or unmounted while a command is running
      • Fixed a crash when a file watcher was closed while a directory scan was still in flight
      • Fixed project verify skills being rewritten on every session instead of only when a documented command changed
      • Fixed the agent view rendering one line too high and clipping its header when the job list slightly overflowed the screen
      • Fixed background tasks in the web and mobile Remote Control panels showing stale "Running" status by forwarding full task state on every membership change
      • Improved auto mode to ask before running rm -rf on a variable it can't resolve from context
      • Auto-update binary downloads now stream to disk instead of buffering in memory, cutting the updater's peak memory usage by roughly 400 MB
      • Background task notifications now explicitly state that no human input has occurred, preventing fabricated in-transcript approvals from being acted on
      • Improved agent view: sessions that edit, merge, comment on, or push to an existing PR now link it in claude agents
      • Improved agent view: rows now show a colored state word and a classifier-written headline instead of raw tool call text, and the peek opens with full status including the exact ask for blocked sessions
      • /doctor is now a full setup checkup that can diagnose and fix issues; /checkup is its alias
      • Reserved the "Claude Browser" MCP server name (alongside "Claude Preview") ahead of the Claude Desktop pane rename; user-configured MCP servers can no longer register under either name
      • Fixed Cowork VM-mode local-agent sessions failing to start with "Not logged in Β· Please run /login" on CLI 2.1.203+
    3. πŸ”— Register Spill Ownership rss

      _The following is an internal Slack message I sent to my Amp teammates after I had a conversation with one of them about ownership. It 's only lightly edited.

      I shared it before, but not here, because I didn't think too much of it. Then today, someone said their CTO shared my post with them and I thought: well, now I have to put it in the newsletter, don't I? So here we are._

      Below, after the Slack post, I added some thoughts on juniors on how I see this advice applying to them.

      Just had a (great) conversation about ownership and engineering here and I realized that I often use the phrase "ownership" or allude to it, but haven't explained what "ownership" means to me in a while.

      So, ownership.

      If I ask you "can you own this?" or "can you take care of this?" or "are you on it?" -- what I'm doing is I'm asking you to own it, to own the solution of a problem from end to end. From "we have a problem" to "we don't have to think about it again."

      That means, when you say that you're owning something, the expectation is that you…

      • Think about what the problem actually is. Maybe you already have a solution in mind, without having thought about what we're actually trying to solve here. Maybe you think "the problem is that we need to migrate from using X to using Y", but that's not a problem, that's a solution. The problem is likely something like "performance is bad", "it's not stable", "it fails for customer x". Maybe there's other possible solutions to that? Think about those. What are the tradeoffs? What's the best solution to go with considering these tradeoffs?

      • Think about edge cases. What are they? Which ones are important? Which ones can we ignore?

      • Think about failures. Network failures are a given, for example. How do we handle them? Retry? Well, how often? How long?

      • Think about data flow. How much data is involved here? Does data need to be migrated? Cleaned up? How can I get my hands on data to properly test this? What invariants are in the data? What assumptions do I have about the shape of the data that I haven't confirmed yet?

      • Think about how you'd test this. How can I know that what I built is correct or not? Are tests enough? Do I need to manually poke at things? Is the difference visible on a screenshot or in a video?

      • How would we announce this? How do we communicate it? Can you picture it? How does it fit into the larger picture of our roadmap? Questions or concerns in that area -- push back! ask!

      • Do the work, with precision, with care, with a sense of urgency, with calmness. Do not half-ass things. Before you merge, ask yourself: am I proud of this? would I show this to John Carmack and say "here's what I built, under these constraints, with these tradeoffs?"

      • Test it manually. Yes, there's automated tests. But in 99% of cases you can manually test or confirm that what you built works: you can run it yourself, you can ask an agent to run through test scenarios, you can poke at the data before and after, you can take screenshots, you can make a demo. Are you sure that what you did actually solves the problem?

      • Make sure it lands in production and works in production. Is it deployed? Did the deploy fail? Do you need to activate a feature flag? Does the feature flag work? Can you use it in production? Can you confirm it's actually deployed?

      • If you think your colleagues needs to know about this change, because it's new feature they should all test, or it's a new convention in codebase, or maybe it's a tricky thing everybody needs to be aware of, or something else: let them know! Do not underestimate peripheral vision: knowing that person X yesterday changed the behavior of how Z works might save person Y three hours of debugging today when a bug report related to Z comes in.

      • Do customers need to know? Who reported the bug? Who's blocked? Let them know.

      • Does the world need to know? Announce that it's out.

      • Are there follow-ups? Do you need to check on what you shipped in the logs? A week later maybe?

      Yes, that's a lot. And there's actually more, because I'm sure I forgot some stuff.

      But that's how you build a product in a small team. We don't have PMs, we don't have a Q&A department. We're small, but we're great , we can do all of that.

      And it's always okay to ask for help, it's okay to ask questions, it's okay to redo things and triple-check. What's not okay is to implicitly assume that someone else will do the things here that you haven't thought about.

      " How does this apply juniors? You can't expect them to really do all of that?"

      I've been asked these questions, or variations of them, after I shared the thoughts above and here's my answer.

      I do not expect juniors to do all of these things right away. But I would expect them to read through the list and aspire to one day be able to do all of these things. Until then, they can and should ask for help.

      In fact, I don't expect anybody to always do all of these things for everything. It's a mental checklist of things to consider -- problem, edge cases, tradeoffs, deployment, customers, messaging, … -- but for quite a few things there aren't edge cases to consider. Or big tradeoffs to weigh. Or deployment is a solved problem. And maybe someone else does the messaging for you.

      And I imagine that most of these things you shouldn't even consider when you work in a company with, say, 5000 employees. I've never worked in a company that large, only startups, so I can't speak to how to successfully ship a software feature at Apple, end to end.

      But when you work in a small company in which there's only a single department, when you want to build things you're proud of, when you work with me and you say own something, I expect you to keep these things in mind and run through them before you declare something as done.

      You know what you should own? A subscription to this newsletter:

    4. πŸ”— navidrome/navidrome v0.63.0 release

      Navidrome 0.63 brings a long-awaited upgrade to lyrics: full support for synced sidecar lyrics in multiple formats (TTML, ELRC, SRT, YAML and LRC), including word-by-word karaoke timing and multi-voice (agent) layers, exposed to clients through the new OpenSubsonic v2 lyrics extensions. A huge shoutout to @ranokay, who not only contributed the code for these lyrics enhancements, but also helped shape the OpenSubsonic extension specification behind them. Search also gets noticeably smarter: exact matches now rank above prefix matches (searching for "MØ" brings MØ to the top instead of burying it), and artists with short or non-ASCII names that were previously unfindable now show up correctly.

      The other big theme of this release is performance for large libraries and offline-first clients. Full-library synchronization via search3 (the way clients like Symfonium mirror the whole library) is now flat at every offset instead of degrading with depth, roughly 30-50x faster at deep offsets and about 20x faster for a complete sync on a ~1M-track library, and a related pagination-integrity fix eliminates the duplicate and short pages that could corrupt those syncs. Alongside it, getRandomSongs is about 13x faster on the same library size, and a batch of database improvements (annotation-index- friendly smart playlist filters, leaner list-count queries, and new composite indexes for album/artist song sorts) makes everyday operations anywhere from ~9x to ~160x faster. Finally, a heads-up on a behavior change: sharing is now enabled by default, and can be turned off with EnableSharing=false.

      Security

      • Enforce per-library access on playlist import and sharing paths. In multi-library setups, three read paths did not consistently apply per-library restrictions: M3U import path resolution, shared-playlist track loading, and public share-scoped streams. A user with access to only some libraries could resolve or be served tracks from libraries they weren't assigned to. All three now respect the user's (or share owner's) library access. (#5640 by @deluan)
      • Resolve symlinks to their real target when classifying files during scan, preventing symlinked entries from being misclassified. (ecba19a08 by @deluan)

      Configuration Changes

      Status | Option | Description | Default
      ---|---|---|---
      New | Scanner.ArtistSplitExceptions | List of artist names that must never be split by tag separators (e.g. "Tyler, The Creator"). (#5701) | [] (empty)
      New | Scanner.IgnoreDotFolders | Whether to skip folders whose name starts with a dot when scanning. Set to false to index dot-prefixed folders. (#5568) | true
      Changed | EnableSharing | Sharing is now enabled by default. Set to false to restore the previous behavior. (#5714) | true
      Changed | LyricsPriority | New sidecar lyrics formats added to the default priority list. (#5076) | .ttml,.yaml,.yml,.elrc,.lrc,.srt,.txt,embedded

      For a complete list of all configuration options, see the Configuration Options documentation.

      Lyrics

      • Add structured sidecar lyrics support with OpenSubsonic v2 karaoke cues and agent layers: TTML, ELRC, SRT and YAML sidecar files are now parsed with word-by-word timing and multi-voice information. (#5076 by @ranokay)
      • Allow lyrics plugins to return lyrics in any supported format, not just LRC. (#5632 by @deluan)
      • Keep the player's lyrics in sync on track change and seek, so the previous song's lyrics no longer linger. (7303c9ca4 by @deluan)

      Search

      • Rank exact matches above prefix matches in search results. (#5704 by @deluan)
      • Fix artists with short or non-ASCII names being unfindable after the FTS5 search migration. (#5703 by @deluan)

      UI

      • Add RosΓ© Pine themes. (#5664 by @draconivis)
      • Fix transient jump to a wrong song when switching tracks in the web player. (#5676 by @deluan)
      • Fix profile self-edits not reporting success or failure. (#5699 by @deluan)
      • Fix Nautiline theme font and width on mobile devices. (#5590 by @devBoi76)
      • Fix DefaultLanguage not being applied on app startup. (#4000 by @deluan)

      Scanner

      • Add Scanner.ArtistSplitExceptions to protect artist names from being split by tag separators. (#5701 by @deluan)
      • Add Scanner.IgnoreDotFolders to allow indexing dot-prefixed folders. (#5568 by @deluan)
      • Fix playlists not being imported when the first scan runs before any admin user exists. (#5609 by @deluan)

      Subsonic API

      • Add OpenSubsonic work and movement attributes, improving classical music metadata for compatible clients. (#5659 by @deluan)
      • Speed up getRandomSongs on large libraries with two-phase random selection, about 13x faster on a 1M-track library. (#5618 by @deluan)
      • Speed up artist search3 pagination at deep offsets, roughly 5-8x faster on a 300K-artist library. (#5620 by @deluan)
      • Speed up search3 empty-query (browse-all) pagination: response times are now flat at any offset, 30-50x faster at deep offsets, making a full ~1M-track library sync about 20x faster overall. (#5601 by @deluan)
      • Make "recently added" album order reproducible and consistent with the RecentlyAddedByModTime setting. (#5678 by @deluan)

      Smart Playlists

      • Extend isMissing/isPresent operators to BPM, bit depth and many text fields. (#5603 by @deluan)
      • Speed up smart playlists that filter on play count, rating or loved status, up to ~14x faster end-to-end (the underlying query alone is over 300x faster). (#5662 by @deluan)
      • Speed up smart playlists with many negated artist/tag rules, ~160x faster on a real-world case with 120 rules on a 323K-track library. (#5607 by @deluan)
      • Fix isMissing/isPresent operators on ReplayGain fields. (#5585 by @deluan)

      Recommendations

      • Match similar and top songs across all artists credited on a track, improving results for collaborations. (#5668 by @deluan)
      • Match ListenBrainz top songs for collaborations using all credited artist MBIDs. (#5670 by @deluan)
      • Speed up top/similar song matching with batched lookups, up to ~14x faster on large batches. (#5635 by @deluan)
      • Fix song matching to use artist credits, so artist-MBID specificity works and collaborators match correctly. (#5637 by @deluan)

      Plugins

      • Add a navidrome plugin CLI for managing and inspecting plugins. (#5682 by @deluan)
      • Expose the song Matcher as a host service for plugins. (#5643 by @deluan)
      • Share plugin DTOs via a common types package, simplifying plugin development. (#5655 by @deluan)

      Artwork

      • Speed up image resizing and WebP encoding/decoding, up to ~30% faster with far fewer allocations. (#5652 by @deluan)
      • Fix artist folder images being incorrectly served as album art. (#5596 by @deluan)
      • Fix WebP crash on 32-bit ARM; WebP encoding is now disabled by default in Docker images. (#5606 by @deluan)

      Transcoding

      • Preserve source metadata when transcoding downloads. (#5628 by @deluan)
      • Enforce server-side player MaxBitRate on all stream paths. (#5611 by @deluan)
      • Honor the player's forced transcoding format in the web UI playback flow. (#5613 by @deluan)
      • Fix partially-written transcodes being served from the cache after a server crash. (#5657 by @deluan)

      Server

      Database

      • Speed up song sorting by album and artist with new sort-order indexes, ~19x faster on large libraries on a cold cache. (#5706 by @deluan)
      • Skip library filtering when a non-admin user has access to all libraries, making song counts ~19x faster on a 920K-track database. (#5696 by @deluan)
      • Skip unnecessary annotation joins when counting items, up to ~9x faster list counts, with even larger gains on a cold cache. (#5694 by @deluan)
      • Make PRAGMA optimize errors non-fatal at startup. (bd3192be0 by @deluan)

      Translations

      New Contributors

      Full Changelog : v0.62.0...v0.63.0

      Helping out

      This release is only possible thanks to the support of some awesome people!

      Want to be one of them?
      You can sponsor, pay me a Ko- fi, or contribute with code.

      Where to go next?

    5. πŸ”— HexRaysSA/plugin-repository commits sync repo: +2 releases rss
      sync repo: +2 releases
      
      ## New releases
      - [DriverBuddyReloaded](https://github.com/voidsec/driverbuddyreloaded): 2.5.1
      - [ida-cyberchef](https://github.com/hexrayssa/ida-cyberchef): 0.3.2
      
    6. πŸ”— MetaBrainz libdiscid 0.7.0 rss

      Version 0.7.0 of libdiscid has been released. libdiscid is a C library that allows applications to easily calculate MusicBrainz and freedb disc IDs from audio CDs or CD TOC details. It also can extract MCN and ISRC information.

      This release fixes several issues with the build system and addresses compiler warnings. As a compile time option it is now possible to have methods returning URLs to use HTTPs instead of HTTP, see then changelog for details. Thanks to Riku Viitanen for this contribution. Also the binary packages now include a build for the Windows ARM64 platform.

      Version 0.7.0 of libdiscid provides the following changes:

      • Add DISCID_USE_HTTPS build flag: If set, the functions discid_get_submission_url and discid_get_webservice_url will generate URLs using the HTTPS protocol instead of HTTP. This might break existing applications that rely on the exact URL structure being returned, hence this flag is disabled by default.
        NOTE: DISCID_USE_HTTPS will become the default in a future release. Please
        update your software to not rely on the exact URL structure being returned.

      • CMake: Fix pkg-config .pc file not being relocatable

      • Autotools: Fix "make docs" not including examples
      • Mac: Fix compiler warning about deprecated use of IOMasterPort
      • Fix compiler warnings about use of strncpy
      • Consistently use CRLF for newlines in versioninfo.rc
      • Provide Windows ARM64 binary builds

      More details on libdiscid, information on available language bindings, and downloads of the source code and pre-compiled binaries for macOS and Windows can be found on the libdiscid page. See also the API documentation for details on how to use the library.

    7. πŸ”— anthropics/claude-code v2.1.204 release

      What's changed

      • Fixed hook events not streaming during SessionStart hooks in headless sessions, which could cause remote workers to be idle-reaped mid-hook
    8. πŸ”— Ampcode News Agents, Anywhere rss

      You can now start new agents remotely from ampcode.com anywhere you can run amp:

      That means, in addition to running agents in orbs, you can now run agents on any machine you want: your laptop, your server, your cloud dev box, your Raspberry Pi. Your lawn mower even, if it has a shell.

      Enable it by using the command amp: enable remote creation of threads or with the setting:

      // ~/.config/amp/settings.json
      
      {
          "amp.remoteThreadCreation.enabled": true
      }
      

      Once enabled, every Amp client you start will accept and run new threads in its working directory.

      Runner Mode

      You can also use the new runner mode with:

      amp --no-tui
      

      That starts Amp in a headless mode in which it only waits to start and run new threads:

      You can start multiple runners on the same machine, as long as they're started in different directories. Each runner is uniquely identified by host and working directory. Directories don't have to be version controlled. They can be anything, even home directories.

      You can start agents anywhere now.

      Walkthrough

      Here's Thorsten with a walkthrough: