Na'aman Hirschfeld @nhirschfeld.bsky.social · 12/10/2026I need some hobbies 😁. I'm apparently the #1 committer in Germany on GitHub. 130
Na'aman Hirschfeld @nhirschfeld.bsky.social · 26/09/2026Same split in code. "Is this function AI-generated" has no reliable answer, and a generated function can be byte-identical to a hand-written one. "Do I own this path" does have one, and the repo already stores it. That is the question poly asks. Rust, MIT: github.com/Goldziher/poly 030
Na'aman Hirschfeld @nhirschfeld.bsky.social · 26/09/2026AI text detection is a similarity score, not a determination. The false positives and false negatives are structural, and they get worse as human writing converges on generated style. Provenance answers what detection only estimates: drafts, timestamps, history. 340
Na'aman Hirschfeld @nhirschfeld.bsky.social · 31/08/2026poly cannot be published to crates.io. Its crates pin git deps for oxc, biome and rubyfmt, and crates.io forbids that in a published crate. So the prebuilt binary is the product, not the source. A constraint I did not choose, and would not now reverse. github.com/Goldziher/poly 020
Na'aman Hirschfeld @nhirschfeld.bsky.social · 31/08/2026Wrote a lint rule that catches todo!() and unimplemented!() shipping to prod. Ran it on 48 repos: 324 findings, 320 in generated FFI glue. Of the 4 real ones, 3 were stubs and 1 was a mock. 25% false positives on a sample of 4 is not evidence. It ships off. 000
Na'aman Hirschfeld @nhirschfeld.bsky.social · 31/08/2026Filed an issue against my own linter today. The MCP report promotes errors to a top level list, so a caller can gate without walking every record. Skipped only exists per record. The cheap check catches failed and misses not checked. github.com/Goldziher/poly/issues/19 000
Na'aman Hirschfeld @nhirschfeld.bsky.social · 31/08/2026Someone on r/git corrected me today. pre-commit stashes with git diff-index and git apply, so a lost stash is not in the reflog at all. Only commits are. My post said reflog. Wrong, and the real story is worse. poly does not stash. github.com/Goldziher/poly 000
Na'aman Hirschfeld @nhirschfeld.bsky.social · 30/08/2026poly also ships an MCP server. 11 tools over stdio, TOON output so it does not eat an agent's context, and results that separate "checked and clean" from "we failed to check it". That second distinction matters more than it sounds. github.com/Goldziher/poly 140
Na'aman Hirschfeld @nhirschfeld.bsky.social · 30/08/2026Repo, MIT licensed: github.com/Goldziher/poly 020
Na'aman Hirschfeld @nhirschfeld.bsky.social · 30/08/2026Every polyglot repo I work on needs a dozen linters, each with its own runtime to install. So I wrote poly. One Rust binary, ~30 languages linted and formatted in-process, one TOML config. Django is 3,113 files in 0.82s. No Node, no Python, no Go toolchain. MIT. github.com/Goldziher/poly 151
Na'aman Hirschfeld @nhirschfeld.bsky.social · 29/08/2026Writing polyglot libraries, I often find myself needing to cleanup my machine from all sorts of build artifacts. Its basically a daily occurrence I prune 200GB of build artifacts and caches, which is annoying. I therefore give you VOOM, inspired by Dr. Seuss: github.com/Goldziher/voomgithub.comGitHub - Goldziher/voom: Fast, safe, parallel polyglot build-artifact and cache pruningFast, safe, parallel polyglot build-artifact and cache pruning - Goldziher/voom 010
Na'aman Hirschfeld @nhirschfeld.bsky.social · 25/08/2026Wrote up the whole thing: the PR, what I decided I was and wasn't entitled to take, and what the loop actually turns up. dev.to/nhirschfeld/285-commits-opened-and-closed-in-one-minute-what-i-do-with-forks-that-never-upstream-24k2 150
Na'aman Hirschfeld @nhirschfeld.bsky.social · 25/08/2026I have sympathy. Upstreaming costs you: match the conventions, argue with a maintainer who has opinions, wait. If your agent carries the patch forward on every merge, the maths genuinely changes. But the bug they fixed quietly is the one you hit next month. github.com/xberg-io/xberg 120
Na'aman Hirschfeld @nhirschfeld.bsky.social · 25/08/2026The instruction has to be narrow. "Review this fork" gets a summary nobody needs. "Find where this fork worked around or defended against upstream behaviour, ignore their own features" gets three real places. I'm not reading 150k lines of someone else's merge. An agent will, and won't skim. 100
Na'aman Hirschfeld @nhirschfeld.bsky.social · 25/08/2026The loop: list all 576 public forks. Drop the stale ones and the ones with no commits ahead of the fork point, which is nearly all of them. Pull the comparison diff on what's left. Hand each to an agent. File what it finds. 100
Na'aman Hirschfeld @nhirschfeld.bsky.social · 25/08/2026I don't want their code. I want to know what broke. A fork that's diverged for six months is a bug report in the most honest format there is. Someone hit a problem in production and fixed it, and the diff says exactly where. So the output isn't patches. It's issues. 100
Na'aman Hirschfeld @nhirschfeld.bsky.social · 25/08/2026Xberg is MIT. Nothing obliges anyone to upstream anything, and I don't want there to be. That was the point of picking MIT. But MIT cuts both ways. Nothing stops me reading public forks either. 100
Na'aman Hirschfeld @nhirschfeld.bsky.social · 25/08/2026Obvious what happened. Someone maintains a private fork with an agent, told it to merge upstream into their branch, and it aimed at the wrong repo. It was the second time. Four days earlier the same branch did it with 130 commits. I read through it. There were real bug fixes in there. 100
Na'aman Hirschfeld @nhirschfeld.bsky.social · 25/08/2026I woke up to a PR on Xberg opened and closed during the night. Title: Claude/merge. Nothing else in it. 285 commits, 377 files, 150k added lines, zero deletions. Opened 22:32, closed 22:33. Someone's agent had merged upstream the wrong way round and pointed the PR at me. 110
Na'aman Hirschfeld @nhirschfeld.bsky.social · 13/08/2026It isn’t smooth. Claude and Codex expose startup hooks and nothing else, so a tool can’t push a message to an agent. You nudge them, they poll. Fair security call, still limiting. What it buys me is QA loops: one agent finds a bug that belongs to another and files it there. 010
Na'aman Hirschfeld @nhirschfeld.bsky.social · 13/08/2026The part I actually use it for: the agents talk to each other. Each registers, creates or joins rooms scoped by path glob, repo or id, and sends DMs. In that screenshot the crawlberg agent has proven a causal chain that spans two tools, and is messaging the other tool’s owner. 100
Na'aman Hirschfeld @nhirschfeld.bsky.social · 13/08/2026Making all of it work together is basemind. A persistent daemon that scans the code and gives agents code maps, code search, semantic search over the repo’s docs, and git analysis. It’s installed as a plugin in Codex and in every Claude tab up there. github.com/Goldziher/basemind 100
Na'aman Hirschfeld @nhirschfeld.bsky.social · 13/08/2026Shipping for 16 languages meant quality control was going to be 16 toolchains. So I wrote poly. One binary wrapping oxc, ruff and other Rust engines, with its own generic linting on top. Every convention baked in. It’s my strongest guardrail on AI. github.com/Goldziher/poly 100
Na'aman Hirschfeld @nhirschfeld.bsky.social · 13/08/2026All five, plus spikard (a web framework I build on the side), use alef to generate bindings for 14 languages. 15 for html-to-markdown, which also does R. One engine, one binding generator, no hand-written FFI per language. github.com/xberg-io/alef 100
Na'aman Hirschfeld @nhirschfeld.bsky.social · 13/08/2026xberg uses html-to-markdown for HTML, liter-llm for model access, tree-sitter-language-pack for code intelligence, and crawlberg for crawling. crawlberg uses html-to-markdown and liter-llm as well. So a fix in one of them lands in three places. github.com/xberg-io 110
Na'aman Hirschfeld @nhirschfeld.bsky.social · 13/08/2026This is my screen on a normal day. Nine agents in iTerm2 tabs, one per repo. I’d run more but the 16" display runs out first. Double-click a tab and it zooms full screen, so that’s my zoom in and out. They’re all in one workspace, and the repos depend on each other. 110
Na'aman Hirschfeld @nhirschfeld.bsky.social · 06/08/2026the part I keep thinking about is how it got caught. a stranger audited my type inference from a Reddit comment, because the output is a file you can read. nobody finds this class of bug in an ORM's runtime behaviour. there's nothing to point at. 010
Na'aman Hirschfeld @nhirschfeld.bsky.social · 06/08/2026so the faithful type is a union on that bit, not per-column optionals. we don't emit it because per-column optionality is the one shape that maps to all 10 targets, and Go can't express the union at all. opt-in, TS only. github.com/Goldziher/scythe/issues/… 100
Na'aman Hirschfeld @nhirschfeld.bsky.social · 06/08/2026what does hold: total is NOT NULL in orders, so total === null happens exactly when the join found nothing. every NOT NULL column from the outer side shares one bit. the flat type admits { total: null, notes: "gift" }, a row the query cannot produce. 100
Na'aman Hirschfeld @nhirschfeld.bsky.social · 06/08/2026the query LEFT JOINs orders onto users. we emit total: string | null and notes: string | null. his claim was that they're always both null or both string. but notes is nullable in its own right, so a matched row really can come back as total: "9.99", notes: null. 100
Na'aman Hirschfeld @nhirschfeld.bsky.social · 06/08/2026posted scythe's generated TypeScript on r/typescript yesterday. someone replied that the row type was wrong. he was half right, and the half he got wrong turned out to be the more interesting half. 110
Na'aman Hirschfeld @nhirschfeld.bsky.social · 06/08/2026thanks! that's the right way to hold it, honestly. it's a swap-in for an EasyOCR-shaped hole rather than something to go find a use for. 020
Na'aman Hirschfeld @nhirschfeld.bsky.social · 06/08/2026the write isn't ours: hf-hub is content-addressed with on-disk locking, so parallel fetches of the same file dedupe rather than race. sceptre then checks a pinned sha256, so a truncated blob fails loudly. undocumented though: github.com/Goldziher/sceptre/issues… 000
Na'aman Hirschfeld @nhirschfeld.bsky.social · 05/08/2026That's the bet behind scythe: SQL in, a typed data access layer out, for 10 languages. The agent writes SQL it can verify; you review SQL you can understand. Neither of you is guessing about a runtime. github.com/Goldziher/scythe 011
Na'aman Hirschfeld @nhirschfeld.bsky.social · 05/08/2026Write the .sql file instead and you both get the same artifact. The agent gets a compiler that catches a nullable LEFT JOIN column, or an UPDATE with no WHERE, immediately. You get a diff you can actually read. 110
Na'aman Hirschfeld @nhirschfeld.bsky.social · 05/08/2026An ORM makes the agent simulate runtime behaviour it can't see: lazy loading, identity maps, a query builder assembling strings at call time. So it guesses. And you review the guess without seeing the SQL either. 111
Na'aman Hirschfeld @nhirschfeld.bsky.social · 05/08/2026LLMs are genuinely good at writing SQL. It's declarative, the syntax has barely moved in 50 years, and the training corpus is enormous. Where agents fall apart with databases isn't the query. It's the ORM layer wrapped around it. 110
Na'aman Hirschfeld @nhirschfeld.bsky.social · 05/08/2026starmetal: one self-hosted binary that proxies your package registries. pip, npm, cargo, maven and more through a single cache with integrity and policy. Go/Zig/Swift have no index protocol to proxy, so it mirrors their git repos instead. Rust, MIT, early (v0.4). 121
Na'aman Hirschfeld @nhirschfeld.bsky.social · 04/08/2026Fair point. It uses the standard HF cache, so HF_HOME / HF_HUB_CACHE relocates it (e.g. a mounted CI cache). A `sceptre download` subcommand pre-seeds that dir in your image build or a cached step, so runtime stays offline. Downloads are sha256-verified first-party ONNX. 100
Na'aman Hirschfeld @nhirschfeld.bsky.social · 04/08/2026Thanks! The Rust OCR ecosystem is thinner than it should be, so glad it's useful. Kick the tires and open an issue if you hit anything rough. 120
Na'aman Hirschfeld @nhirschfeld.bsky.social · 04/08/2026Code, the reproducible benchmark harness, and golden parity fixtures: github.com/Goldziher/sceptre . I build and maintain it, happy to answer anything. 120
Na'aman Hirschfeld @nhirschfeld.bsky.social · 04/08/2026Library, CLI, or MCP server. Native ONNX Runtime, or a pure-Rust backend (tract) for WASM and Android. Models fetch once from Hugging Face, cache locally, then run offline. MIT. 230
Na'aman Hirschfeld @nhirschfeld.bsky.social · 04/08/2026Measured like-for-like on CPU (43-image corpus): ~2.8x higher throughput warm, ~3x lower peak memory (6.6 vs 22.6 GB). A cold one-shot CLI run is still ~4.4x faster than EasyOCR warm. Accuracy at parity across 8 scripts, CJK to Cyrillic to Telugu/Kannada. 110
Na'aman Hirschfeld @nhirschfeld.bsky.social · 04/08/2026Sceptre: EasyOCR reimplemented in Rust. EasyOCR is accurate but Python-only (a PyTorch stack). Sceptre matches its output using the same OCR approach (CRAFT detection, gen2 CRNN, CTC over ONNX) and ships as one static binary with no Python. 1123
Na'aman Hirschfeld @nhirschfeld.bsky.social · 02/08/2026Repo, docs, and the full changelog: github.com/xberg-io/xberg . I build and maintain it, happy to answer anything. 010
Na'aman Hirschfeld @nhirschfeld.bsky.social · 02/08/2026On our reproducible PDF benchmarks it's #1 on native PDFs: composite quality 0.958 vs 0.837 for the next best, and table/reading-order fidelity 0.949 vs 0.612 for docling. Also #1 on scanned OCR. Image OCR is #2 for now, improving in v1.1. 120
Na'aman Hirschfeld @nhirschfeld.bsky.social · 02/08/2026The core is pure Rust now (pdf_oxide replaces pdfium). It ships 15 language bindings from one engine: Python, TS, Rust, Go, Java, C#, PHP, Ruby, Elixir, Dart, Swift, Kotlin, Zig, plus CLI/REST/MCP. Full mobile support and in-browser WASM inference. 120
Na'aman Hirschfeld @nhirschfeld.bsky.social · 02/08/2026Xberg v1 is out. It's the successor to Kreuzberg: a content-intelligence framework with a Rust core that extracts text, tables, layout and metadata from 101 document formats, plus code, audio/video, and URLs. Local-first, CPU-only, MIT. 131
Na'aman Hirschfeld @nhirschfeld.bsky.social · 25/07/2026Every open-weight model drop splits the room: benchmark hype vs how-was-it-trained. Both skip the point. A frontier-quality open model drops that capability's price to near zero. No lab gets to rent it back as a moat. I build local-first tooling. That pressure on closed pricing is what sticks. 140