I'm Jeremy, a developer in Australia. I write mostly Go and Rust, and I'm a little obsessed with making software fast and lean.
My interests wander: tools for AI coding agents, running AI locally, IT admin tools, peer-to-peer networking, security and bug hunting. Most of my public work so far is fixes in other people's projects, listed below. The tools I build myself are released under Sigilet Labs.
By day I look after systems and infrastructure, and manage open source projects, for a not-for-profit. Everything here is personal work.
If you work on similar things, I'd like to hear from you. Open an issue on any of my repos and say hello.
-
soc-thief: sleep through the night while it reads your Wazuh alerts. You get one Discord message in the morning, and a page only when something looks like a breach. An AI model gives advice but can't hide an alert. It runs on your own host, reads Wazuh with a read-only account, and sends nothing to a hosted model unless you opt in.
-
ai-quota-meter: shows your remaining Claude Code quota on the status line, using Anthropic's own numbers, and switches on Codex's built-in quota display. A single static binary with no network access.
Fixes merged into other people's projects. One dot per merged pull request.
Every merged pull request, one line each
- neuledge/context#125: only skip repo-meta filenames at the scan root
- neuledge/context#126: Go module support for the docs registry
- neuledge/context#166: skip test and example directories only at the repo root
- neuledge/context#173: generic types and JSX inside code examples stay in the docs index
- neuledge/context#175: section titles keep words inside bold, italics, links and code, so Python doc sections stop being indexed as "Introduction"
- neuledge/context#190: prose sections with long link URLs are indexed instead of skipped as tables of contents
- neuledge/context#206: pages without a frontmatter title are named by their
# h1instead of their file name, so Python doc pages stop showing up aslogging-cookbook.html - neuledge/context#208: long Markdown sections are split outside code blocks, so a code example with blank lines in it stays in one piece
- yetone/magpie#88: the gateway reports a Claude reply cut off by the context window as cut off
- yetone/magpie#128: gateway ids made in the same clock tick stay unique
- Yeachan-Heo/oh-my-claudecode#4152: the git guardrail hook also catches
git --no-pager pushand other global options - Yeachan-Heo/oh-my-claudecode#4160: the code-simplifier hook reads the global config from
~/.configon Linux, where the docs put it - Yeachan-Heo/oh-my-claudecode#4161: Copilot and Cursor rule globs like
**/*.pyalso match files at the top level - Yeachan-Heo/oh-my-claudecode#4177: the directory-context hook stops adding a sibling folder's README and AGENTS.md
- microsoft/conductor#572: a
$before a{{ }}expression no longer stops a workflow loading - volcengine/OpenViking#5448:
ovcli.confaccepts theoidc_tokenand trusted-mode settings the Rust CLI already reads - NVIDIA/SkillEvaluator#168: the PII scan stops reporting Chrome User-Agent versions as IP addresses
- freescout-help-desk/freescout#5683: toolbar icons, stars and menu toggles can be reached with Tab and pressed with Enter or Space
- microsoft/SkillOpt#295: the sleep harvester stops reading skill text Claude Code injects as things the user typed
- dmno-dev/varlock#1169: the standalone binary can start its encryption helper when run from a directory the user cannot enter, so
varlock cache clearworks for service users - freescout-help-desk/freescout#5692: confirmation dialogs focus the primary button, so Enter confirms
- freescout-help-desk/freescout#5693: deleting a conversation opens the next active one when that is the after-send setting, as a status change already does
- vectorize-io/hindsight#4870: the MCP
recalldocs say whatmax_tokenscounts - axllent/mailpit#742:
_and%in a search match themselves instead of acting as wildcards - axllent/mailpit#743: address searches like
from:"Marks & Spencer"find names containing&or\ - axllent/mailpit#757: negated
larger:,smaller:,after:andbefore:searches return exactly what the plain search leaves out, so a message on the boundary is no longer in both results or in neither - axllent/mailpit#759: the link check finds a link at the very start of a plain-text message, such as a password-reset email that is just the link
- morluto/rea#1985: .NET assemblies precompiled for Linux or macOS open in the managed inspection tools instead of failing as an unsupported architecture
- morluto/rea#2730:
rea uninstallremoves only its own row from a shared DeepSeek Harness patch, and keeps the user's settings and comment - morluto/rea#2117: WebAssembly modules too large to disassemble get a short size-limit error instead of 33 MB of output and advice to run
rea doctor - morluto/rea#2096:
rea setupfor Hermes accepts aconfig.yamlthat holds only comments or a---marker, and keeps them - morluto/rea#2116: comparing two .NET assemblies pairs each member with its own type and name first, instead of matching it to an identical member of another type
- morluto/rea#3059: comparing two builds of a .NET assembly pairs members whose signatures name the same types at different metadata rows, instead of reporting them removed and added
- curl/curl#23469:
-O -Jfalls back to the name from the URL when the server sends an emptyfilename="",.or.., instead of failing with error 23 - ublue-os/ucore#458: uCore on aarch64 no longer runs out of space in
/bootwhen rebasing from Fedora CoreOS, because it drops the devicetree files CoreOS drops - holepunchto/dht-rpc#133: closing a session releases each of its requests from the congestion window once, not twice
- jgm/pandoc#12007: converting a Jupyter notebook with long cell output no longer slows down with the square of its length (a #7744 notebook: 41 s to 1.4 s)
- zvec-ai/zvec-grep#229: managed
rgsearches keep their globs and ignore rules when the search path starts with. - axllent/mailpit#764: a message Mailpit cannot parse is rejected with
554instead of accepted with250 queuedand silently dropped - morluto/rea#7225: Chrome DevTools HAR files whose
serverIPAddressis a bracketed IPv6 address are inspected instead of refused as a whole - google/osv-scanner#3214: Rust call analysis logs and skips an
.rlibwhose ar member header has a negative or non-numeric size, instead of panicking and ending the whole scan - getkin/kin-openapi#1424: a
$refunder a header'scontentis resolved, so a valid OpenAPI document no longer fails validation withfound unresolved ref
- stripe/link-cli#370:
--authwithout a path is refused instead of logging out the default session - ahmad-a0/silverbullet-mcp#19: the note-editing tools only write
.mdnotes - christian-korneck/claude-desktop-rpm#4: the RPM spec builds a working Claude Desktop 2.x on Fedora (bump to 2.2553.1)
- Mbed-TLS/mbedtls#11002: the
cert_writeandcert_reqsample programs accept IPv6 addresses insan=IP:without overflowing the stack, and keep each IP entry's own address (backports #11003, #11004) - aicodeking/leanrea#2: the skill's piped commands run as written, instead of passing
|to the first command as an argument - holepunchto/hyperdht#317: after a relayed connection upgrades to direct, the server remembers the direct path to the client for reuse instead of the relay's address
- Exiv2/exiv2#9553: image files shorter than 80 bytes, such as a tiny GIF or BMP, are recognised instead of reported as an unknown image type
- jgm/ipynb#4: notebooks whose outputs have a null execution count, which the format allows, can be read instead of being rejected
- PaesslerAG/gval#124: with decimal arithmetic, division or modulo by zero returns an error instead of a panic that crashes the program
- dim13/otpauth#45: an MD5 entry no longer crashes code generation for 3 in 16 codes
Issues filed: SkillSpector#638, #639, #640, SkillEvaluator#167, silverbullet-mcp#20, chrome-agent#12, scc#783, hindsight#5371, gitea#39651, rea#4797, #4806, #7226, pandoc#12008, SkillOpt#316, ar#16, dicom#392, gnostic-models#31, libopenapi#693, gval#123, otpauth#44.



