🏡


to read (pdf)

  1. I don't want your PRs anymore
  2. JitterDropper | OALABS Research
  3. DomainTools Investigations | DPRK Malware Modularity: Diversity and Functional Specialization
  4. EXHIB: A Benchmark for Realistic and Diverse Evaluation of Function Similarity in the Wild
  5. Neobrutalism components - Start making neobrutalism layouts today

  1. June 21, 2026
    1. 🔗 r/reverseengineering Reverse once, run forever: designing client-side defenses that assume the attacker has already read every line rss
    2. 🔗 r/reverseengineering I reverse engineered Windows Copilot into a free OpenAI compatible API (GPT-4o, no API key, no billing) rss
    3. 🔗 r/reverseengineering Hello can somebody deobfuscat this? rss
    4. 🔗 r/reverseengineering NØW — Word-Based Shellcode Encoder rss
    5. 🔗 r/reverseengineering Note20 ABL Odin out-of-bounds read rss
  2. June 20, 2026
    1. 🔗 IDA Plugin Updates IDA Plugin Updates on 2026-06-20 rss

      IDA Plugin Updates on 2026-06-20

      Activity:

      • atelier
        • 5e89dc0c: fix(skills): make perf-review stack-agnostic for distribution
        • 410417f0: fix(skills): make perf-review stack-agnostic for distribution
        • dae584cd: feat(skills): add perf-review skill with measured perf gates
        • 62b12a81: test: realign stale assertions with the shipped agent/tool surface
        • f6cd080c: docs(readme): rocket emoji on hero + reformat benchmark tables
      • disrobe
        • eb995072: skip the grpc serve e2e on windows where the spawned server deadlocks…
        • 1318b65c: skip the gnu-bash base64 oracles on macos where bsd base64 differs
        • 0d6362a4: use is_ok_and in the bash base64 probe to satisfy clippy
        • 96e8427c: skip bash base64 oracle when gnu base64 (-w0/-d) is unavailable (eg m…
        • d26bc23b: skip the stack-string oracle when gcc emits no elf object (eg macos m…
        • c7b54edf: skip the gcc resolver oracle when the object is not elf (eg macos mac…
        • 70f3f91f: revert py-decompile chain to source-terminal output to preserve mcp/c…
        • 4843e690: make py-decompile chain manifest deterministic for portable goldens a…
        • 841eca10: js: emit the recovered source as a chain child so auto surfaces it un…
        • 1d7a2a12: fix electron e2e to read recovered js from the mixed fan-out output l…
        • a4a44ba1: js: bless the chain golden for the mixed fan-out sidecar output
        • 8da0b285: lua chain pass emits recovered source + lua.manifest.json sidecar so …
        • a4196d29: js-deob chain: emit detection/recovery/pipeline sidecars as auto chil…
        • 038502a6: py.deob auto/chain emits the peelresult manifest sidecar
        • 906a9ebb: py.decompile chain emits source + manifest sidecar for auto parity
        • 0f4263b3: py.disasm chain emits the structured .dis.json sidecar child so auto …
        • 691b23f6: native packer-unpack chain pass emits dedicated sidecars for auto parity
        • ddd4c944: make external-tool round-trip gates skip when the tool is unavailable…
        • 8766e68f: fmt the hand-edited capabilities rules and frisk tests
        • 6bbaaa90: recover swift protocol requirements from __swift5_protos descriptors
      • rikugan
        • a9bcac0c: chore(release): bump version to 1.2.1
        • 0566d891: Merge branch 'feat/ui-review-sprint1'
      • ToCode
        • 3eba5881: Merge pull request #9 from buzzer-re/dev/improves
        • 942b3320: Gate IDA cache rebuild behind -purge-cache
        • 31b19fb5: Recover from a broken cached IDA database
        • bad636ac: Rebuild stale IDA caches and relativize absolute source paths
        • 4f3502f2: Merge pull request #8 from buzzer-re/dev/improves
        • 3e932ecd: Ignore missing elftools imports in mypy
        • 11073372: Import DWARF line/file info in the IDA loader
        • dba1445a: Fix IDA source/type recovery to use the real IDA APIs
    2. 🔗 earendil-works/pi v0.79.9 release

      New Features

      • Chat-template thinking compatibility - OpenAI-compatible custom providers can map Pi thinking levels into chat_template_kwargs, enabling vLLM/Hugging Face chat-template models such as DeepSeek to use provider-native thinking controls. See Custom Provider API Types and OpenAI Compatibility.
      • GLM-5.2 provider improvements - GLM-5.2 now has corrected Fireworks OpenAI-compatible routing and OpenRouter xhigh thinking support, improving /model behavior and high-effort reasoning for GLM-5.2 users. See Model Options.

      Added

      • Added inherited configurable chat-template thinking support for OpenAI-compatible providers that use chat_template_kwargs, such as DeepSeek models behind vLLM (#5673).

      Fixed

      • Fixed inherited Fireworks GLM-5.2 metadata to use the OpenAI-compatible Chat Completions endpoint with reasoning_effort support (#5923).
      • Fixed same-directory session switches to reuse imported extension modules while preserving fresh extension instances and lifecycle events (#5905).
      • Fixed deep session branches taking quadratic time to build context or branch paths (#5909).
      • Fixed inherited OpenRouter GLM-5.2 metadata to expose xhigh reasoning and send OpenRouter's native xhigh effort (#5770).
      • Fixed inherited Markdown streaming code fence rendering so partial closing fences no longer make code blocks shrink or flicker while content streams (#5846 by @xl0).
      • Fixed fuzzy edit matches to preserve untouched line blocks instead of rewriting the whole file through normalized content (#5899).
      • Fixed bash commands through legacy WSL bash.exe to pass scripts over stdin so shell variables expand in the target bash (#5893).
      • Fixed /model to hide GitHub Copilot models that are unavailable to the authenticated account (#5897).
      • Fixed /model selector search to rank exact provider-prefixed matches before proxy-provider model ID matches (#5892).
    3. 🔗 r/reverseengineering Built a full Android RE suite that runs on-device — Radare2 CFG graphs, 8 Java decompilers (CFR, Procyon, Krakatau…), Flutter & il2cpp support rss
    4. 🔗 r/reverseengineering Reverse engineered Pixel 7 Tensor G2 access rss
    5. 🔗 r/reverseengineering DOS Game "F-15 Strike Eagle II" reversing project needs DOS test pilots rss
    6. 🔗 r/reverseengineering GitHub - lautarovculic/ioscpy: A macOS CLI that mirrors and controls a jailbroken iPhone over USB. rss
    7. 🔗 r/reverseengineering sterrasec/apk-interceptor: Android deeplink, Intent, and WebView bridge assessment helper rss
    8. 🔗 Stephen Diehl Prism: An Impure Functional Language With Typed Effects rss

      Prism: An Impure Functional Language With Typed Effects

      This is going to be a very nerdy post so bear with me. Here is a function. Read it the way you would read any other function, and then tell me its type.

      fn fib(n) =
        var a := 0
        var b := 1
        repeat(n) fn
          let t = a + b
          a := b
          b := t
        a
      

      That is a mutable loop. There is a var, there is assignment, there is a temporary so the swap does not eat itself. It is, line for line, the fib you would write in Python after deciding that recursion was a young person's game.

      Its type is Int -> Int, it is functional but in place. There is no effect type even though the function has effects, because the effects are not observable from outside the function. As far as anyone calling it is concerned, this function is pure. It mutates two variables in place and then, before the door closes behind it, sweeps up the evidence and leaves no fingerprints. And the compiler does it all for you. It's the code you would write in Python with types you get from OCaml and no monads.

      This is Prism, a proof of concept functional compiler I've been working on for the last three years, built around modeling effects with modern types inspired by the intellectual lineage of OCaml 5, Haskell and Koka. The big idea of the last five or six years of functional programming is that effects are real, effects are fine, and the interesting question is not how to avoid them but how to put them in the type system and then optimize them until they cost nothing.

      Effects Are Interfaces

      The one idea you need is the algebraic effect handler. An effect declares operations; a handler gives them meaning. Here is a producer that yields a sequence and has no idea who is listening:

      effect Gen {
        ctl yield(Int) : Unit
      }
      
      fn produce(n) : !{Gen} Unit =
        if n == 0 then
          ()
        else
          yield(n)
          produce(n - 1)
      

      The !{Gen} in the type is the function confessing, in writing, that it performs the yield operation and someone upstream had better deal with it. Now we hand the same producer to two different handlers:

      fn total(n) =
        handle produce(n) with
          yield(v, k) => v + k(())
          return r => 0
      
      fn count(n) =
        handle produce(n) with
          yield(v, k) => 1 + k(())
          return r => 0
      

      The k is the continuation, the rest of the computation, reified as an ordinary value you can hold in your hand. total resumes it and adds; count resumes it and counts. A handler can ignore k entirely (that is an exception), call it once (that is state, or a generator), or call it many times. This last one is the move that makes algebraic effects more than sugar. Here a handler finds Pythagorean triples by resuming the same continuation once per candidate, which is to say it explores a whole search tree using nothing but straight-line code and a handler that says "yes, and also try the other branch":

      effect Amb {
        ctl choose(Int) : Int,
        ctl reject(Unit) : Int
      }
      
      fn triple(n) : !{Amb} Int =
        let a = choose(n)
        let b = choose(n)
        let c = choose(n)
        if a > 0 && b > 0 && a <= b && a * a + b * b == c * c then
          a * 10000 + b * 100 + c
        else
          reject(())
      
      fn solutions(n) =
        handle triple(n) with
          choose(m, k) => flatten(map(\(i) -> k(i), range(0, m)))
          reject(u, k) => Nil
          return r => Cons(r, Nil)
      
      fn main() =
        let sols = solutions(14)
        println(length(sols))
        println(sum(sols))
      

      choose(n) offers a value in 0..n-1 and reject() prunes a dead branch, and because the handler resumes k once for every candidate, triple reads like a function that just picks three numbers.

      If you have used OCaml 5 this will feel familiar, except OCaml keeps its effects out of the types, so you find out about an unhandled one at runtime, in production, on a Friday. If you have used Haskell this will also feel familiar, except in Haskell you would be assembling a monad transformer stack, lifting each operation through every layer by hand, and explaining to a junior colleague that a monad is just a monoid in the category of endofunctors, what's the problem. Prism's effects are row polymorphic. They union structurally across calls. There is nothing to stack and nothing to lift, because there is no tower, only a set.

      One Trick, Five Ways

      Once effects are first class, a remarkable number of ideas from the last thirty years of language design turn out to be unified under the same mechanism:

      Exceptions are a handler that throws away the continuation. A clause marked final ctl discards k, so its body's value becomes the handler's result and the rest of the computation is simply abandoned. No Result threading, no ? confetti up the call stack, just direct-style code that stops:

      fn safe_grade(n) =
        handle grade(n) with
          final ctl abort(msg) => concat("invalid: ", msg)
          return r => r
      

      And because an exception is just a label in the effect row, you get extensible exceptions for free. Each distinct failure is its own operation, so the row in a function's type spells out exactly which exceptions can escape it, the way !{Gen} spells out that it yields. There is no root Exception class to inherit from and no hierarchy to edit; a new exception is just a new label. They union structurally across calls, so a function that can abort and a function that can timeout compose into one whose row carries both. Handling one of them discharges its label and leaves the rest in the row, which means partial recovery is something the type system tracks rather than something you promise in a comment:

      effect Abort   { ctl abort(String) : Unit }
      effect Timeout { ctl timeout(Int)  : Unit }
      
      -- fetch's row spells out both failures it can raise
      fn fetch(id) : !{Abort, Timeout} String =
        if id < 0  then abort("bad id")
        if id > 99 then timeout(id)
        "ok"
      
      -- discharge Timeout with a fallback; Abort still escapes
      fn with_default(id) : !{Abort} String =
        handle fetch(id) with
          final ctl timeout(_) => "cached"
          return r => r
      

      The handler peels Timeout off, so with_default is left carrying exactly !{Abort}, no more and no less. Java's checked exceptions wanted to be this and could not, because they were welded to the class hierarchy instead of being an open, structural set.

      Generators and streams are a producer that performs emit, transformers that catch it and re-emit, and a consumer that folds. A pipeline is handlers nested around one producer, which means there is no intermediate list, by construction:

      srange(1, n).smap(square).skeep(even).stake(5).ssum()
      

      Stopping early, the stake(5), is just a handler dropping a continuation once it has what it needs. Cancellation produces garbage, and that garbage is reclaimed at a statically known point with no collector involved, which is the good part we will come back to. The stream library was inspired by Haskell's pipes and conduit.

      Lenses are not a library anymore they are language-integrated. They are record-update paths plus the memory model. Given three nested record types, one path expression reaches arbitrarily deep and sets several fields at once:

      type Vec2   = Vec2   { x: Int, y: Int }
      type Player = Player { pos: Vec2, hp: Int }
      type Game   = Game   { player: Player, score: Int } deriving (Lens)
      
      let g2 = { g | player.pos.x = 30, player.hp = 95, score = 110 }
      

      That rebuilds the spine of the nested record, and when the value is uniquely owned, each rebuild reuses the cell it just took apart, so a functional update compiles to a pointer write. No optic types are allocated, nothing is composed at runtime, the path is just addresses. The entire optics ecosystem, the van Laarhoven encoding, the profunctor zoo, the operators that look like a cat walked across the keyboard, all of it collapses here into one syntax rule and a memory discipline. And when you genuinely need to pass an accessor around, deriving (Lens) hands you score_of and with_score as ordinary functions:

      let g3 = with_score(g2, 200)   -- score_of(g3) == 200
      

      They are boring functions, which is the highest compliment in functional programming!

      Mutable state is the var from the opening. Each var desugars to a private effect with get and set operations, discharged by a handler installed at the end of its block. The state never escapes, an analysis rejects any closure that would try to smuggle it out, and the enclosing function keeps its empty row. This is the loop you would write in Python with the signature you would want in Haskell and none of the State monad plumbing in between.

      Failure is the most fun, because it is functional logic programming sneaking in through the effect row. An anonymous Fail effect makes "this expression might not produce a value" a thing the type system already knows how to talk about. fail() performs it, guard(cond) performs it when a check is false, and the consumers read like a wish list:

      let port = cfg.at_map("port") ?? cfg.at_map("https") ?? 443
      let off  = customer?.tier?.discount ?? 0
      let bill = [item for item in sof(cart), if prices.at_map(item) > 4]
      

      ?? falls back when the left side fails. ?. chains through options and short-circuits. The comprehension guard prunes elements that fail instead of crashing. And because var is itself just handler sugar, an entire block can be transactional: transact snapshots every live variable, runs the body in a failure context, and rolls everything back if it fails, so an overdrawn account behaves as if the purchase never happened.

      transact
        balance := balance - price
        guard(balance >= 0)
        balance
      else
        0
      

      Five features. One underlying mechanism, viewed through a five dimensional prism. And that lovely idea is the namesake!

      Modern Types

      So far we haven't seen a lot of type signatures which is the point, most of the time you can write down quasi-Python-looking code and inference is decidable and predictable via the usual complete-and-easy Dunfield-Krishnaswami algorithm. You annotate only where you genuinely cross into higher-rank territory, which is rare, and the algorithm meets you exactly at that boundary. A function can demand a genuinely polymorphic argument, declared with a forall on the binder, and then use it at several types in one body:

      fn pick(g : forall a. (a) -> a) : Int =
        if g(true) then
          g(10)
        else
          g(20)
      
      fn main() =
        println(pick(\(x) -> x))
      

      g is forced to be polymorphic, so pick may apply it to a Bool and an Int in the same breath, which is why main can only hand it the identity function and not, say, a number. A Damas-Milner core would have unified a with Bool on the first call and rejected the second; here the forall survives into the argument.

      Ad-hoc polymorphism is type classes, but Lean-flavored: instances are named values, not anonymous magic resolved by global coherence. You write given Ord(a) to ask for a dictionary, and you can name exactly which one you want at the call site when more than one is in scope:

      instance ordDesc : Ord(Int) {
        fn cmp(x, y) = int_cmp(y, x)
      }
      
      sort_by_ord(xs)            -- the default Ord(Int)
      sort_by_ord[ordDesc](xs)   -- this one, reversed
      

      The instances you do not care about, you do not write. One deriving clause off a type declaration synthesizes the boring ones, and the field accessors too:

      type Vec2 = Vec2 { x: Int, y: Int } deriving (Eq, Ord, Show, Lens)
      
      with_x(v, 7)   -- a derived setter, and FBIP-reused when v is unique
      

      Classes also feed pattern matching, which is the part that tends to make PL people sit up. A pattern can name a class method as its view, and then that one pattern deconstructs every type with an instance, dispatched by dictionary exactly like a method call:

      pattern First(n) for Peek = view peek
      
      fn head_or(x : c, d : Int) : Int given Peek(c) =
        match x of
          First(n) => n
          _ => d
      

      First(n) matches a Box, a Range, or anything else that is Peek, and head_or is generic over all of them at once. The pattern is as polymorphic as the function around it.

      Some ad-hoc polymorphism does not even need a class. show is type-directed: the compiler infers the static type of its argument and synthesizes a structural printer from the real constructor names, recursing into fields, with no instance to write and no runtime type dispatch (the printer is monomorphized from the static type, so it never reads a runtime tag to decide how to print):

      show(42)                   -- "42"
      show([1, 2, 3])            -- "[1, 2, 3]"
      show((7, false))           -- "(7, false)"
      show(Node(Leaf, 1, Leaf))  -- "Node(Leaf, 1, Leaf)"
      

      And the third axis is the one the rest of the post is really about: the same row variable that makes effects composable makes them polymorphic. Here is a higher-order function that calls its argument twice and adds the results. The argument's effect row is a variable e, which is to say twice does not care what f does, only that it returns an Int:

      fn twice(f : (Unit) -> Int ! {| e}) = f(()) + f(())
      

      The {| e} is "this row, and whatever else." Each call site unifies e with the actual row of the thunk it passes, and that is the whole trick: one definition serves a pure argument, an effectful one, and an effectful one of a completely different effect, with no overloads and no wrapping.

      fn pure_use() =
        twice() fn(u)
          21
      

      Here e unifies with the empty row {}. No effect is performed, so no handler is needed, and the result is just 42. Now force the same twice to carry an effect through:

      fn tick_use() =
        handle twice(\(u) -> tick(())) with
          tick(u, k) => \(n) -> k(n)(n + 1)
          return r => \(n) -> r
      

      The thunk performs Tick, so e unifies with {Tick}, and the surrounding handle discharges exactly that one label. Swap in a thunk that performs Say instead and e becomes {Say}; twice itself never changed. A handler only ever names the labels it wants, and e quietly carries everything else along, which is what lets these functions compose without a transformer stack to thread them through.

      The same machinery, three times: one definition, abstracted over types, over dictionaries, and over effects.

      Zero-cost Abstractions

      At this point the cynical hater reader (hi Hacker News!) is thinking the thing most armchair peanut gallery types think about elegant abstractions, which is: sure, but what does it actually cost. Algebraic effects have a reputation. The textbook implementation reifies your whole computation into a free monad, a tree of "here is an operation, and here is a function for what to do with its result," and then an interpreter walks that tree allocating a small cell at every single operation. It is beautiful and it is a heap allocation per yield.

      Prism does not do that on the path that matters. The fast path is evidence passing in the Koka lineage, with my own deviations noted where they matter: instead of reifying the computation and reaching for the handler, it carries the active handler clause to each operation site as an ordinary parameter. A do op becomes a direct call. So we don't need a tree, or interpreter loop, or cell. The only allocation is one closure per handler when you install it, which is O(handlers), not O(operations). You can perform yield a billion times under a handler that was allocated exactly once.

      The free monad is still in the building, because some patterns genuinely need it (a computation that escapes into a data structure, a truly multishot resumption, a masked handler). But it is the fallback, not the default, and the compiler proves which one you are in.

      Now point this at the stream pipeline from earlier:

      for n in srange(1, 11).smap(square).skeep(even) do
        print(n)
      

      An interprocedural flow analysis works out, across function boundaries, exactly which effect evidence each producer and transformer needs, and threads it through. The whole chain lowers to a single loop with zero intermediate lists and zero per-operation cells. This is essentially Haskell-like stream fusion, but the thing Haskell achieves with rewrite rules that fire only if you hold your imports correctly and the wind is blowing precisely the right direction while Mercury is in retrograde, and what Rust achieves by monomorphizing iterator adapters into one another at the type level. Here it falls out of the effect compiler, because once emit is a direct call to a known clause, inlining the clause into the producer is just inlining.

      The cleanup, meanwhile, is the good part promised earlier, and it is not a garbage collector. Prism uses Perceus reference counting: every heap cell is freed at a statically known point, deterministically, with no pauses and no tracing. And then the clever idea is that we have frame-limited reuse, where a cell you just deconstructed in a pattern match gets handed straight back to the constructor on the other side of the arrow, so map over a uniquely owned list mutates the list in place while remaining, on paper, a pure function returning a new one. The lens update compiling to a pointer write is this same machinery. So is the loop in fib not allocating. Purity and mutation turn out to be the same thing viewed from different ends of an ownership analysis, which is either a deep idea about the nature of computation or quite banal, and I'm not quite sure which.

      The Runtime & LLVM Backend

      If Perceus reference counting sounds familiar, it should: it is the same memory discipline Lean 4 runs on, and for the same reason, a dependently typed proof assistant cannot afford GC pauses any more than a game loop can. Lean compiles to C and links a little runtime that does the counting. Prism does the structurally identical thing, except it emits LLVM IR (through inkwell) and, for the same program, a text MLIR module, and then hands the result to clang to link against one hand-written C runtime, prism_rt.c, about a thousand lines.

      That runtime is deliberately tiny. A heap cell is four-plus words, { refcount, tag, arity, fields... }, and the whole file is the allocator, the rc_inc/rc_dec pair that the compiler sprinkles through the code, the in-place reuse allocator that the FBIP pass targets, and the bignum and string primitives. There is no collector thread, no card table, no safepoints, nothing that runs when your code is not running. The reference counting is not a service the runtime provides at runtime; it is code the compiler already wrote into your program, and the C file is just where the four or five operations it calls happen to live.

      It links against plain libc malloc by default (there is an opt-in mimalloc knob for benchmarking, but the whole thesis is "do not allocate," and a fast allocator only hides the allocations you failed to eliminate). A live-cell oracle asserts the heap balances to zero at exit, so "garbage free" is a property the test suite checks rather than a thing the README asserts.

      Runs In Browser through WASM

      The same interpreter that serves as the differential oracle compiles to wasm, so there is a playground where you can type Prism and run it without installing anything. It runs the program in a worker, and the buttons next to it will dump the inferred type signatures (effect rows and all) and the lowered core IR, so you can watch a var loop or a stream pipeline turn into the thing it actually compiles to. Every example in this post is in the dropdown. Poke at the effect rows; they are the whole point. The full source, the Lean model, and the C runtime all live in the prism repository on GitHub.

      Nerd Stuff

      For completeness, if you have read this far you have clearly made some very questionable life choices (hi fellow traveller!) so here's the PL nerd stuff:

      • Type inference is the usual SOTA bidirectional and higher-rank, the complete-and-easy Dunfield-Krishnaswami algorithm, so rank-N polymorphism works without you annotating your way out of it.
      • Typeclasses with Lean-style named instances (instance ordInt : Ord(Int)), explicit override (sort_by_ord[ordRev](xs)), and deriving (Eq, Ord, Show).
      • A mostly OCaml-ish-shaped surface syntax : layout blocks, dot chains (xs.over(f).keep(g).sum()), with sugar for continuation-passing code, string interpolation, effect row aliases.
      • Deep recursion runs in constant stack, both natively (tail calls, and tail recursion modulo a constructor) and in the interpreter (it is essentially a more advanced version of the old CEK machine, so nothing in your program can blow the host stack).

      And, for the genuinely afflicted, the full intellectual lineage. Obviously standing on the work of many FP giants, but the ones that are most directly inspired Prism's design are:

      The thesis, if a toy project gets to have one, is that "purely functional" was always a slightly defensive name for a good idea. The good idea is that effects should be visible, typed, and composable. You do not need to forbid them to get that; you need to track them. And once you are tracking them honestly, the compiler has enough information to make them free, which is the part the purity narrative never promised you, because it was too busy not making eye contact with the IO monad.

      This compiler is essentially my love letter to the old 2010-20s era of functional programming which was a much simpler and happier time (or maybe that's just the rose-tinted glasses of youth in the ZIRP era). This compiler is a toy, it is for all intents and purposes useless except maybe as kind of a piece of art from a bygone time before the Transformer-era of programming. The world we're headed to doesn't really have a place for this kind of thing anymore. We're increasingly headed to a world in which maximally probabilistic hilariously-uninteresting Typescript increasingly runs most of the world as we babysit these token extruders while the economy and markets become increasingly automated by agents. While this makes me kind of sad, it doesn't mean we still can't build this kind of thing just for fun and that's what I did here. Maybe the future of functional programming languages is increasingly niche-but-economically-irrelevant and becomes more like a hobby pursuit for the few of us who still love it for the intellectual beauty of the underlying ideas. So I built it anyways, and it runs, and it was a blast to build. And just maybe that's enough, in this brave new world of software.

    9. 🔗 mahmoudimus/ida-sigmaker v1.9.2 release

      sigmaker.py - IDA Python Standalone Python Release

      Release Information

      What changed

      Fixed

      • Canceling XREF signature generation now stops the XREF loop and keeps completed results. If Cancel fired while one per-xref signature was being generated, UserCanceledError was caught as a generic per-candidate failure and the loop moved on to the next xref. XREF generation now stops immediately and prints the complete xref signatures found so far. This does not touch the SIMD speedup paths. (#55, #56)

      Description

      This is a standalone release of the IDA Pro signature maker plugin. The file sigmaker.py contains the complete plugin code that can be directly imported into IDA Pro.

      Installation

      1. Copy sigmaker.py to your IDA Pro plugins directory
      2. Restart IDA Pro
      3. Use Ctrl+Alt+S to access the Signature Maker menu

      License

      See the main repository for license information.

  3. June 19, 2026
    1. 🔗 IDA Plugin Updates IDA Plugin Updates on 2026-06-19 rss

      IDA Plugin Updates on 2026-06-19

      Activity:

    2. 🔗 modem-dev/hunk v0.16.0 release

      What's Changed

      • Refreshed Hunk's built-in theme system and changed the default theme to github-dark-default, with a simpler theme config setting and a View → Themes… / t selector for switching themes by @benvinegar in #441 and #450
      • Added built-in theme contrast coverage and documented automatic theme selection by @benvinegar and @jrpat in #450 and #451
      • Fixed standalone binaries so a repo-local bunfig.toml can no longer run Bun preloads before Hunk starts by @jrpat in #452 and #456
      • Made the theme selector less jumpy by requiring an explicit click or keyboard action before previewing a theme, while keeping mouse-wheel scrolling by @benvinegar in #453
      • Honored explicit split layout in static pager output for captured hosts like LazyGit by @benvinegar in #434
      • Improved review-stream responsiveness by reducing offscreen React mounting work while preserving adjacent syntax-highlight prefetching by @benvinegar in #450
      • Let session comment cleanup commands remove human c notes with comment rm user:*, comment clear --include-user, and comment clear --all by @benvinegar in #435
      • Adopted Changesets for release-note fragments to reduce changelog conflicts across pull requests by @benvinegar in #426
      • Expanded regression coverage across CLI parsing, VCS adapters, session broker/commands, patch parsing, mouse selection, sidebar resizing, and PTY flows by @benvinegar in #440, #442, #445, #444, #448, #449, and #455

      New Contributors

      Full Changelog : v0.15.3...v0.16.0

    3. 🔗 r/reverseengineering Analyzing Bytes: Pre-Disassembly Static Binary Analysis rss
    4. 🔗 HexRaysSA/plugin-repository commits sync plugin-repository.json rss
      sync plugin-repository.json
      
      No plugin changes detected
      
    5. 🔗 HexRaysSA/plugin-repository commits fix duplicated plugin idalib-rust-bindings (#33) rss
      fix duplicated plugin idalib-rust-bindings (#33)
      
    6. 🔗 Hex-Rays Blog IDA 9.4: Apple Dyld Shared Cache workflow improvements rss

      IDA 9.4: Apple Dyld Shared Cache workflow improvements

      Over the years, the Apple ecosystem (iOS, macOS, …) has seen steady gains in security, application load-time, and more. One of the cornerstones enabling those is the "Dyld Shared Cache" (DSC): a highly specific collection of common system libraries, pre-optimized on many fronts and used across applications.

    7. 🔗 r/reverseengineering Martyx00/VulnFanatic-NG: BianryNinja plugin for identifying vulnerabilities in decompiled binaries with both programmatic scans and LLM support. rss
    8. 🔗 earendil-works/pi v0.79.8 release

      New Features

      • Selective provider base entry points - SDK users can pair @earendil-works/pi-ai/base and @earendil-works/pi-agent-core/base with explicit provider registration to keep bundled applications from including unused provider transports. See pi-ai Base Entry Point and pi-agent-core Base Entry Point.
      • Mistral prompt caching - Mistral sessions now use provider-side prompt caching with session affinity and cached-token usage/cost accounting. See API Keys and Environment Variables.
      • Post-compaction token estimates - Compact results and compaction events now include estimated post-compaction token counts so clients can show the approximate context reduction. See RPC compact and compaction events.
      • OpenRouter Fusion alias - openrouter/fusion is available as a built-in OpenRouter model alias. See API Keys.

      Added

      • Added inherited @earendil-works/pi-ai/base and @earendil-works/pi-agent-core/base entry points for selective provider registration in bundled applications (#5348 by @FredKSchott).
      • Added inherited Mistral prompt caching using the pi session ID as prompt_cache_key, including cached-token usage and cost accounting (#5854).
      • Added estimated post-compaction token counts to compact results and compaction events (#5877).
      • Added the inherited OpenRouter Fusion alias as openrouter/fusion (#5866 by @dannote).

      Fixed

      • Updated vulnerable runtime dependencies, including undici and the packaged protobufjs transitive dependency.
      • Fixed compaction to refuse sessions with no eligible messages instead of producing empty summaries (#4811).
      • Fixed successful overflow-triggered auto-compaction to avoid retrying completed assistant responses (#5720).
    9. 🔗 MetaBrainz Phishing attempts using MetaBrainz messages rss

      There have been reports of users receiving phishing messages via the MetaBrainz messaging service.

      Remember: MetaBrainz staff will never ask for your password. MetaBrainz staff will never ask you to log in to a third-party site (or 'verify' your username and password in any other way).

      Staff are also likely to email you about account issues directly from an @metabrainz account rather than the user-to-user messaging service.

      You can go a step further and apply these rules to every website and service… you are now 99% phishing-proof!

      Below is an example of a reported phishing message. This is not a message from staff. It is an attempt to compromise a MetaBrainz account by getting a user to enter their username and password into a third-party website.

      If you receive phishing attempts (or spot other scams) via MetaBrainz services please leave a comment here. There is also a thread on the community forums discussing the phishing messages.

    10. 🔗 r/reverseengineering BSim-foundry: pre-built function signatures for zlib, OpenSSL, mbedTLS, SQLite, libcurl and 24 more. headless + GUI + IDA/BN via SightHouse rss
    11. 🔗 Ampcode News Custom Agents rss

      You can now create custom agents in Amp with plugins.

      You can use these custom agents as your main Amp agent, or as subagents. You can use them as a small part of a tool pipeline that you invoke with amp -x. Or you can spawn 25 custom worker agents, then switch between them.

      Each custom agent comes with a custom orb color.

      Here is how you define a custom agent in an Amp plugin:

      // .amp/plugins/focused-reviewer-agent.ts
      import type { PluginAPI } from '@ampcode/plugin'
      
      export default function (amp: PluginAPI) {
          // Create the agent
          const reviewer = amp.createAgent({
              name: 'focused-reviewer',
              model: 'openai/gpt-5.5',
              instructions: [
                  'You are a focused code-review subagent.',
                  'Inspect only the files and concerns named by the caller.',
                  'Return concise findings with severity, evidence, and suggested fixes.',
              ].join(' '),
              tools: 'all',
              display: { label: 'reviewer', color: '#d97706' },
          })
      
          // Register a tool. This agent acts as a subagent
          amp.registerTool({
              name: 'focused_review',
              description: 'Run a focused code-review subagent.',
              inputSchema: {
                  type: 'object',
                  properties: {
                      request: { type: 'string' },
                  },
                  required: ['request'],
              },
      
              async execute(input, ctx) {
                  // Run a one-shot agent turn
                  const result = await reviewer.run(input, {
                      parentThreadID: ctx.thread.id,
                  })
                  return result.text
              },
          })
      
          // Or register the agent as a selectable main thread mode
          amp.registerAgentMode({
              key: 'focused-reviewer',
              description: 'Code Review Expert',
              agent: reviewer.definition,
          })
      }
      

      Threads

      Once you have defined an agent, you can create threads:

      // Spawn a new thread
      const thread = await reviewer.createThread({
          // Tell the UI switch to this thread
          show: true,
      })
      
      // Get an existing thread
      const thread = amp.threads.get(input.threadID)
      

      The Thread object lets you interact with a thread in many different ways, and is where the real power comes in.

      Send a message to a Thread

      Add a new user message to a thread by calling thread.appendUserMessage(). The call returns as soon as Amp has accepted the message; it does not wait for inference to complete before returning.

      await thread.appendUserMessage({
          type: 'user-message',
          content: 'Review the auth changes in this branch.',
      })
      

      Wait for the Agent's response

      When you do want to wait, call waitForResponse() on the thread. It resolves with the next assistant message after the agent finishes its turn.

      const reply = await thread.waitForResponse()
      

      Example: Spawn an async thread that responds to the main thread

      These are just a few primitives provided by the Plugin API. Together, they compose into unique workflows. An example used on the Amp team: spawn an agent in an asynchronous thread, and give it the tools it needs to respond to the parent when it needs to.

      amp.registerTool({
          name: 'start_async_review',
          description: 'Start a review in a background thread.',
          inputSchema: { type: 'object', properties: {} },
          async execute(_input, ctx) {
              const thread = await reviewer.createThread({
                  parentThreadID: ctx.thread.id,
              })
      
              await thread.appendUserMessage({
                  type: 'user-message',
                  content: [
                      'Review the auth changes in this branch.',
                      `When you are done, call send_to_thread with threadID ${ctx.thread.id}`,
                      'and include your review in the message.',
                  ].join(' '),
              })
      
              return `Started background review in ${thread.id}.`
          },
      })
      

      Full documentation is in the manual. Happy Hacking.

  4. June 18, 2026
    1. 🔗 IDA Plugin Updates IDA Plugin Updates on 2026-06-18 rss

      IDA Plugin Updates on 2026-06-18

      New Releases:

      Activity:

      • atelier
        • 88b48395: chore: bump to v0.4.20
        • 515396b9: chore: bump to v0.4.19
        • 04079e76: fix(install): pick newest wheel, clean stale ones; cache statusline s…
        • 5fca8f2c: chore: bump to v0.4.18
        • 148f2372: fix(install): make dev kills prod-path MCP servers, spares only .venv…
        • 6b59442d: chore: bump to v0.4.17
        • f9ccf622: feat(index): show 'N of X commits (rest in background)' in git histor…
        • 43269d9a: Merge: linearize grep symbol-span extraction (vscode grep ~240s -> <1s)
        • bd87f039: perf(search): linearize grep symbol-span extraction (quadratic -> lin…
        • 427b2a69: chore: bump to v0.4.16
        • 64998584: fix(init): -no-index on install, 10s lock timeout (was 30s hang)
        • 6cd943cb: fix(install): follow redirects for Content-Length; make release target
        • 6cb7451d: fix(install): bundle AGENTS.atelier.md; show host error output; 30s i…
        • 7ee2f930: chore: bump to v0.4.13
      • capa
        • 29575cac: Merge pull request #3110 from mandiant/dependabot/npm_and_yarn/web/ex…
        • e2154630: build(deps): bump form-data from 4.0.4 to 4.0.6 in /web/explorer (#3109)
        • f28a1505: Merge pull request #3105 from mandiant/dependabot/npm_and_yarn/web/ex…
      • disrobe
        • a9907897: native: detect obfusheader.h by its strip-surviving pointer-shuffle c…
        • e39d29fd: native: detect guardian-rs x86-64 virtualizer by its embedded .vm/.by…
        • b8691069: native: detect rust-obfuscator/cryptify by its CRYPTIFY_KEY decrypt s…
        • 9ccae3de: skip the mio (0.8/1.x) and yaxpeax-arch (0.2/0.3) transitive duplicat…
        • 69983fc9: native: detect obfus.h by its .obfh signature section
        • 818c5e3d: shell: detect real Chameleon long-random variable renames (Invoke-Ste…
        • fc8cfe9e: cover Protector::BitMono in the chain quality_for match (the chain-fe…
        • b887f1d2: dotnet: detect BitMono + tolerate its anti-static-tooling header corr…
        • 47fff2fc: jvm: fold skidfuscator xor-seed integer obfuscation back to literals
        • c61daac2: native: fold real -O0 ollvm -bcf opaque-predicate-or-real-condition b…
        • cde7b2ad: native: lift real -O0 ollvm -sub through stack slots and reduce its x…
        • c5c8bdf6: native: make the synthetic packer-detection test buffers valid PE images
        • af4fe246: rustfmt the frisk-gauntlet temp-dir join (i committed the race fix wi…
        • 191e63df: native: label the Tigress CFF self-authored fixture as not-real-proof…
        • 4ce3b000: native: label the self-authored iced ollvm tests as the linear-chain/…
        • 4a8cb6ec: native: recover real ollvm-16 flattened LOOPS - resolve a case block'…
        • 0c79b882: give each frisk-gauntlet staged corpus its own temp dir (the per-pid …
        • 9bb85f99: native: recover REAL ollvm-16 control-flow flattening - generalize th…
        • aa7fcd7e: php deob: CFG-restructure pass that recovers yakpro goto-flattened co…
        • 32cb2c7b: regenerate the js/jvm/beam chain goldens after the decimal-radix, fin…
      • doki-ida
        • 17a72dfe: Fixing the sticker and adding crawling asset
      • hrtng
        • 13f20220: deinline: fix single block mode
      • ida-domain
        • 1819169c: Fix problems with invalid license for CI tests (#88)
      • project
        • cb289b8d: added access path shortening
      • showcomments
      • zenyard-ida-public
        • 8edba8e6: Sync with 3c18c5fe1f2ddd30b17f09d629f3362309e4913d
    2. 🔗 Simon Willison Datasette Apps: Host custom HTML applications inside Datasette rss

      Today we launched a new plugin for Datasette, datasette-apps, with this launch announcement post on the Datasette project blog. That post has the what, but I'm going to expand on that a little bit here to provide the why.

      The TL;DR

      Datasette Apps are self-contained HTML+JavaScript applications that run in a tightly constrained <iframe> sandbox hosted on your Datasette application. They can use JavaScript to run read-only SQL queries against data in Datasette, and can run write queries too if you configure them with some stored queries.

      Here's a very simple example and a more complex custom timeline example - the latter looks like this:

      Screenshot of a web app titled "Datasette timeline" with "All apps", "Edit app", and "Pin" buttons top-right and a "Full screen" button below them. Inside a bordered panel, the heading "Datasette timeline" sits above a search box reading "Search news, blog posts and releases…" with three checked checkboxes labeled News, Blog, and Releases. Below, text reads "Showing 200 of 1,953 items", followed by a scrollable list of timeline entries. Each entry has a colored tag (blue "BLOG" or green "RELEASE"), a date, a blue linked title, and a paragraph of description. The visible entries are a "BLOG" post dated 2026-06-11 titled "Datasette 1.0a33 with JSON extras in the API", a "RELEASE" dated 2026-06-11 titled "datasette 1.0a33", and a "RELEASE" dated 2026-06-09 titled "llm 0.32a3", each with body text and a "▶ Show more" toggle. A separate panel at the bottom shows a collapsed "▶ 2 log entries" toggle.

      Apps are allowed to run JavaScript and render HTML and CSS. They are limited in terms of access - the <iframe sandbox="allow-scripts allow-forms"> they run in prevents them from accessing cookies or localStorage and they also have an injected CSP header (thanks to this research) which prevents them from making HTTP requests to outside hosts, preventing a malicious or buggy app from exfiltrating private data.

      Datasette Apps started out as my attempt at building a Claude Artifacts mechanism for Datasette Agent, but I quickly realised that the sandboxed pattern is interesting for way more than just adding custom apps in a chat interface and promoted it to its own top-level concept within the Datasette ecosystem.

      They're also a fun way to turn my multi-year experiment in vibe-coded HTML tools into a core feature of my main project!

      You can try out Datasette Apps by signing in with GitHub to the agent.datasette.io demo instance.

      Why build this?

      Since the very first release, Datasette has offered a flexible backend for creating custom HTML apps via its JSON API.

      One of my earliest Datasette projects was an internal search engine for documentation when I worked at Eventbrite - it worked by importing documents from different systems into SQLite on a cron and then serving them through a Datasette instance with a custom HTML+JavaScript search interface that directly queried the Datasette API.

      I had client-side JavaScript constructing SQL queries, which originally was intended as an engineering joke but turned out to be a really productive way of iterating on the app!

      That project, combined with my experience building my HTML tools collection and my experiments with Claude Artifacts, has convinced me that adding a Datasette-style backend to a self-contained HTML frontend is an astonishingly powerful combination.

      Imagine how much more useful Claude Artifacts could be if they had access to a persistent relational database. That's what I'm building with Datasette Apps!

      Neat ideas in Datasette Apps

      Here are a few of the ideas and patterns I've figured out building this which I think have staying power.

      <iframe sandbox="allow-scripts" srcdoc="..."> + <meta http-equiv="Content-Security-Policy" content="default-src 'none'; script-src 'unsafe-inline'; style-src 'unsafe-inline'; img-src data: blob:;">

      This is the magic combination that makes Datasette Apps feasible in the first place. I need to run untrusted HTML and JavaScript on a highly sensitive domain - an authenticated Datasette instance can contain all sorts of private data. The sandbox= attribute lets me run that untrusted code in a way that cannot interact with the parent application - it can't read the DOM, or access cookies, or steal secrets from localStorage. It can however use fetch() and friends to load content (or exfiltrate data) from other domains. But... it turns out if you start an HTML page with a <meta http-equiv="Content-Security-Policy"> header you can set additional policies that lock down access to other domains. I was worried that malicious JavaScript would be able to update or remove that header but it turns out that doesn't work - once set, the CSP policy is immutable for the content of that frame.

      Locked down APIs with postMessage() and MessageChannel()

      Having locked down those iframes to the point that they couldn't do anything interesting at all, the challenge was to open them back again such that they could run an allow-list of operations, starting with read-only SQL queries against specified databases.

      I built the first version of this with postMessage(), which allows a child iframe to send messages to the parent window. I created a simple protocol for requesting that the parent run a SQL query - the parent could then verify it was against an allow-listed database before executing it.

      One of the LLM tools, I think it was GPT-5.5, suggested that postMessage() on its own can be exploited if the iframe somehow loads additional code from an untrusted domain. I don't think that applies to Datasette Apps, but I also believe in defense in depth, so I had GPT-5.5 help me port to a MessageChannel() based transport instead.

      MessageChannel() has the advantage that if a page navigates to somewhere else the channel closes automatically, removing any chance of executing commands sent from an untrusted external page.

      Visible logs, for queries and errors

      If you navigate to the timeline demo and search for the string usercontent you'll pull in some search results that embed images from the user-images.githubusercontent.com domain. This domain is not in the CSP allow-list, so it trips an error.

      Those errors are captured and transmitted back to the parent frame, where they can be displayed in a useful error log. This is meant to make hacking on apps more productive by surfacing otherwise-invisible problems.

      I built an experiment demonstrating that you can even turn this into a one-click-to-allow mechanism for building the CSP allow-list based on what breaks, but I haven't integrated that idea into datasette-apps just yet.

      SQL queries are also visibly logged - scroll to the bottom of the timeline page to see that in action.

      Stored queries for write operations

      I want apps to be able to conditionally write to the database, but this is an even more dangerous proposition than SQL reads!

      My solution involves Datasette's stored queries feature, rebranded from "canned queries" and given a major upgrade in the recent Datasette 1.0a31 - work that was directly inspired by Datasette Apps.

      Users can create a stored write query that performs an insert or update, then allow-list that specific query for an app to use. Usage from code inside an app looks like this:

      const result = await datasette.storedQuery("todos", "add_todo", {
        title: "Buy milk",
        due_date: "2026-06-20",
        priority: "high",
        completed: false
      });

      I'm only just beginning to explore the possibilities this unlocks myself, but my goal is to support full read-write applications built safely as Datasette Apps.

      Copy and paste a prompt to build an app

      The Datasette Apps plugin has no dependency on LLMs at all, but these self-contained apps are the perfect shape to be written by a modern LLM.

      The create app form includes a copyable prompt at the end. This prompt has everything a model needs to know to build a new app, including the schema of any selected databases.

      Screenshot of the lower part of a "Create app" page. At the top is the tail end of an HTML code editor (lines 35–43, closing the script, body, and html tags) and a blue "Create app" button. Below is a section headed "Use AI to build this app" with the text "Describe the app you want in an LLM chat, then copy this prompt in as context so it can generate or revise the app HTML. Paste the result into the HTML editor above." A blue "Copy prompt" button sits above a "▼ Show full prompt" toggle. An expanded text box shows the prompt: "Build a Datasette HTML app. App name: Latest news. Return a complete single-file HTML document. Include <DOCTYPE, CSS, and JavaScript in the same file. This app will run inside a sandboxed iframe protected by a strict Content Security Policy. Important limitations: – Direct network access is disabled by default. – The app cannot fetch from Datasette, localhost, or arbitrary origins. – External fetch() requests only work for exact https:// origins explicitly granted in the app's network access settings. – Remote images are allowed from those same exact https:// origins. Local file previews using data: and blob: image URLs are allowed. – External script tags are allowed from those same exact https:// origins. – External stylesheet links and style elements are allowed from those same exact https:// origins. – history.replaceState(), history.pushState(), history.back(), history.forward(), and history.go() are no-ops in the sandbox. – CORS still applies even when an origin is granted. Use this API for data access: – await datasette.query(database, sql, params?)"

      This means you can click "copy", paste it into ChatGPT or Claude or Gemini, tell it what you need, and there's a good chance the model will spit out the code necessary to build the app.

      If you have Datasette Agent installed your AI assistant will also gain tools to both create new apps and edit existing ones, Claude Artifacts style.

      Screenshot of a "Chat" interface with a "← Back" link top-left and an "EXPORT" button top-right. A blue user message bubble reads "Build an app showing the 5 most recent headlines from the blog_posts table". Below are two collapsed toggles: "► Tool: describe_table" and "► Result: describe_table". A thinking line reads "Thinking: …will transition to creating the application using app_create as the next step." A section headed "Querying Latest Posts" reads "I've successfully queried the blog_posts table for the 5 most recent titles. The SQL query, SELECT title FROM blog_posts ORDER BY datetime_utc DESC LIMIT 5, is working as expected. Now, I will transition to creating the application using app_create as the next step." An expanded "▼ Tool: app_create" box shows escaped JSON HTML: { "html": "...." Below: "Recent Blog Headlines created." with "View app" and "Edit" buttons, a collapsed "► Result: app_create" toggle, and a final message: "The app "Recent Blog Headlines" has been created. It displays the 5 most recent headlines from the blog_posts table in the content database."

      Built with so much AI assistance

      Datasette Apps started life back in April as datasette-agent-artifacts, a plugin I have since renamed to datasette-agent-edit keeping only its editing tools. I built that as one of the first plugins for Datasette Agent, to help get the plugin hooks into the right shape. That first prototype was mainly built using Claude Opus 4.6 in Claude Code.

      When I switched track to Datasette Apps I started with a plan constructed using Codex Desktop and GPT-5.5 xhigh, based on extensive dialog and feeding in both datasette-agent-artifacts and other prototypes I had built.

      Most of the work that followed stuck with Codex, but in the few short days that we had access to Claude Fable 5 I had it run a security evaluation of the product (an ability that would get it banned by the US government shortly afterwards) and it found a very real problem.

      I was allowing users to allow-list CSP hosts for their apps, but Fable pointed out the following attack:

      1. A less privileged user with create-app permission creates an app that queries SQLite for all available tables and selects and exfiltrates all of the data to a host they had allow-listed via CSP.
      2. They then trick an administrator user with access to private data into visiting their app.
      3. ... and the app can now run queries as that user and steal their private data!

      That's clearly unacceptable. I fixed it by restricting the ability to allow-list any domain to a new apps-set-csp permission, which is intended just for trusted staff. Site administrators can also configure Datasette with a list of allowed_csp_origins, which regular users can then select. This means you can do things like allow cdnjs.cloudflare.com and your users will be able to build apps that load extra JavaScript libraries from the cdnjs CDN.

      I've reviewed Datasette Apps extremely closely, especially the security-adjacent parts of it. The critical sandbox and CSP configuration are based on multiple AI-assisted prototypes and tests.

      It's looking good so far

      I'm really pleased with this initial release.

      Datasette is growing beyond its origins as an application for serving read-only data into a much richer ecosystem of tools for doing useful things with that data once it has been collected.

      Datasette's roots are in data journalism. I've always been interested in the question of what comes next after a journalist gets their hands on a giant dump of data about the world. Datasette supports exploring and publishing it. Datasette Agent adds interrogating it with AI assistance. Now Datasette Apps expands that to building custom interfaces and visualizations to help unlock the stories that are hidden within.

      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. 🔗 r/reverseengineering GitHub - Zypherion-Technologies/UnConfuserEx: A ConfuserEx2 deobfuscator with support for anti tamper, compressor, constants, control flow, and resource recovery. rss
    4. 🔗 HexRaysSA/plugin-repository commits sync repo: +1 plugin, +1 release rss
      sync repo: +1 plugin, +1 release
      
      ## New plugins
      - [idasvg](https://github.com/chichou/idasvg) (0.1.0)
      
    5. 🔗 oxigraph/oxigraph v0.5.9 release

      Store: make Transaction and BulkLoader Send and Sync.

    6. 🔗 earendil-works/pi v0.79.7 release

      New Features

      • Automatic theme mode - /settings can choose separate light and dark themes and follow terminal color-scheme changes. See Selecting a Theme.
      • Self-only updates by default - pi update now updates pi only, with pi update --all for updating pi and packages together. See Install and Manage.
      • Extension API helpers - extensions can use CONFIG_DIR_NAME for project config paths and import edit diff helpers for edit-style diffs. See ctx.cwd and SDK Exports.
      • Warp inline images - Warp terminals now get inline image rendering through Kitty graphics detection. See Image.

      Added

      • Added automatic theme mode so /settings can use separate light and dark themes and follow terminal color-scheme changes (#5874).
      • Added inherited Warp terminal image capability detection so inline images render through Warp's Kitty graphics support (#5841 by @dodiego).
      • Exported CONFIG_DIR_NAME from the coding-agent public API so extensions can resolve project config paths without hardcoding .pi (#5869 by @xl0).
      • Exported edit diff helpers (generateDiffString, generateUnifiedPatch, and EditDiffResult) from the public API for extensions that need edit-style diffs (#5756 by @xl0).

      Changed

      • Changed bare pi update to update only pi, added pi update --all for updating pi and extensions together, and clarified extension update prompts.
      • Reserved / in theme names for automatic light/dark theme settings.
      • Updated extension docs, examples, runtime help, trust prompts, and config labels to use the configured project config directory instead of hardcoded .pi paths.

      Fixed

      • Fixed RPC unknown-command errors to include the request id so clients do not hang waiting for a response (#5868).
      • Fixed /model autocomplete and model selection searches to match provider/model queries regardless of whether the provider or model token is typed first.
      • Fixed the tree navigator to horizontally pan deep entries so the selected item remains readable (#5830).
    7. 🔗 r/reverseengineering Rustemsoft unveils Opaquer .NET Obfuscator, a powerful new tool for protecting .NET applications from reverse engineering. The release delivers advanced control‑flow scrambling, string encryption, and metadata hiding with all core obfuscation features available free of charge. rss
    8. 🔗 r/reverseengineering VAXD update: public v1.00 release is now available rss
    9. 🔗 HexRaysSA/plugin-repository commits Fix/EA-762 cap ida versions (#32) rss
      Fix/EA-762 cap ida versions (#32)
      
      * fix(merger): cap idaVersions at latest released IDA (EA-762)
      
      The upstream HCLI index expands open-ended specs like >=9.0 into a concrete
      list that includes unreleased placeholders (e.g. 10.0), so plugin pages
      advertised compatibility with non-existent IDA releases.
      
      - cap_ida_versions() trims idaVersions to <= the latest released IDA in both
        transform paths (sp-aware comparison); prettified ranges follow.
      - LATEST_RELEASED_IDA resolves from env, defaulting to a reviewed constant.
      - justfile + deploy.yml derive it dynamically from the hcli download catalog
        (hcli download --list-tags, authed via HCLI_API_KEY in CI); falls back to the
        default when hcli is unavailable/unauthenticated, so the build never fails.
      
      Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
      
      * revert(EA-762): drop hcli download --list-tags wiring; keep env-overridable cap
      
      plugin-repository is public, so we don't want a Hex-Rays portal API key in CI
      even as a secret. Remove the hcli-based dynamic derivation from the justfile
      (latest-ida recipe) and deploy.yml (HCLI_API_KEY + --list-tags).
      
      idaVersions are still capped via merge_plugins.py's LATEST_RELEASED_IDA — a
      reviewed default (9.4) overridable with the LATEST_RELEASED_IDA env var when a
      new IDA ships. No auth, no secret.
      
      Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
      
      * chore(EA-762): drop redundant cap comments from justfile and deploy.yml
      
      The override mechanism is documented at LATEST_RELEASED_IDA in merge_plugins.py;
      these were duplicate notes on now-generic merger invocations.
      
      * feat(EA-762): derive LATEST_RELEASED_IDA from hcli download catalog in CI
      
      Re-introduce the dynamic IDA-version cap: justfile (latest-ida recipe + dynamic
      merge-plugins) and deploy.yml derive LATEST_RELEASED_IDA from
      `hcli download --list-tags`, authenticated via the HCLI_API_KEY repo secret.
      Falls back to merge_plugins.py's reviewed default when hcli is unavailable or
      unauthenticated, so the build never fails on this.
      
      A GitHub Actions secret is encrypted, runtime-only and log-masked (not in the
      public source); neither sync nor deploy runs on fork pull_request, so there is
      no fork-PR exfiltration path. Use a dedicated download-scoped portal key.
      
      Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
      
      ---------
      
      Co-authored-by: fnania <fnania@hex-rays.com>
      Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
      
    10. 🔗 Console.dev newsletter databow rss

      Description: CLI to query any ADBC database.

      What we like: Run SQL against any ADBC database e.g. DuckDB, BigQuery, Postgres, SQLite. Syntax highlights the query. Output in a table, CSV, JSON, or Apache Arrow. Supports non-interactive queries from the CLI rather than using the TUI.

      What we dislike: Requires an ADBC driver to exist, which means you can’t query some popular databases like MySQL, Clickhouse, etc.

    11. 🔗 Console.dev newsletter Epiq rss

      Description: Issue tracker backed by Git.

      What we like: Manage issues from a TUI, locally-backed by Git so issues live with the code. Works offline and uses append-only events to avoid conflicts (later events take precedence). Uses worktrees to isolate sync from the main dev workflow. Built in kanban board and a web UI.

      What we dislike: The tradeoff is no public web UI for others to view / submit issues.

    12. 🔗 Ampcode News A Faster Librarian rss

      The Librarian is now ~3x faster and 43% cheaper, with the same quality.

      It now runs on GPT-5.5 (no reasoning) with websocket mode and an updated system prompt that encourages more parallel exploration. The Librarian fires ~8 tool calls in parallel per turn, up from ~3 with Sonnet, and wraps up a search in ~5 turns instead of ~15.

      In our internal eval, about a quarter of that speedup comes from OpenAI's websocket mode and the rest from switching to GPT-5.5 with no reasoning:

      Sonnet-4.6 (medium) GPT-5.5 (none)
      Latency (mean) 237s 81s (2.9x faster)
      ↳ gain from websocket ~1.3x
      ↳ gain from model ~2.2x
      Quality (F1, mean) 0.47 0.48
      Average cost $1.21 $0.69

      Here's a comparison:

      How does Kubernetes' HorizontalPodAutoscaler handle missing pod metrics when scaling down — does it assume missing pods are at 100% of their resource requests, or 100% of the target utilization? Cite the function and logic in the source.

      Sonnet 4.6 (left) took 2 minutes and cost $1.08, while GPT-5.5 (right) took 40 seconds and cost just $0.47.