🔭 Machine Learning Engineer based in London — currently building Industrial-scale multi-agent systems @ London Export Corporation.
🧪 Often the founding ML engineer at growing teams, owning the full path from research to deployed, monitored infrastructure.
🎓 Masters in Applied Data Science @ University of London (Distinction)
⚡ Deep interest in LLM Reasoning, Multi-Agent Systems, Low-Latency Inference, and Reinforcement Learning.
🤝 Passionate about open source and writing about ML on Medium.
💬 Ask me about PyTorch, LangChain, vector retrieval, or anything LLM-flavoured.
12 merged fixes across 10 repositories · 490k+ combined stars Real correctness bugs — schema corruption, a security vulnerability, silent training-time no-ops — each reviewed and merged by maintainers.
| Project | Merged fixes | |
|---|---|---|
| ⚡ | vLLM 89k★ | #52528 malformed JSON bodies returned 500 instead of 422 |
| 🧠 | OpenAI · openai-agents-python 28k★ |
#4036 tool-schema corruption · #4089 cross-turn reasoning leak · #4090 guardrail reporting |
| 🤗 | Hugging Face · datasets 22k★ |
#8325 path-traversal vulnerability (CWE-22) |
| 🧩 | Hugging Face · peft 21k★ |
#3503 LoRA+ embedding learning rate never applied |
| 🔎 | Hugging Face · sentence-transformers 19k★ |
#3880 gradient leak in distillation loss |
| 🔶 | Keras 64k★ | #23375 layer config dropped sparse on reload |
| 🎯 | outlines 15k★ |
#1967 Gemini system-instruction handling |
| 🧮 | TheAlgorithms/Python 223k★ |
#2219 job-scraping module — still shipping 5 years on |
| ⚙️ | statsmodels |
#9908 optimizer Hessian handling · #9909 sparse multinomial CI |
| 📈 | yfinance |
#2897 dividend-repair crash |
What each fix actually did →
vLLM — #52528
Thirteen Pydantic mode="before" validators across six OpenAI-compatible endpoints called data.get(...) without checking that data was a mapping. Any request whose JSON body was a bare list, string, or number — trivially reachable by a misconfigured client — raised AttributeError inside validation and surfaced as HTTP 500 rather than a 422 validation error. Now every affected validator short-circuits on non-mapping input so Pydantic reports it properly.
OpenAI · openai-agents-python
- #4036 — the tool-output schema trimmer recursed into
propertiestreating parameter names as schema keywords, deleting any parameter calleddescription/title/exampleswhile leaving it inrequired. The model received an invalid schema with hidden parameters. - #4089 — a reasoning item not immediately followed by its assistant message kept its signed thinking blocks pending, so a previous turn's private reasoning was replayed on a later turn.
- #4090 — output guardrail results were discarded when a tripwire aborted the run, mirroring a fix the maintainers had just landed for input guardrails.
Hugging Face · datasets — #8325
An unsanitized file_name in dataset metadata allowed arbitrary file reads (CWE-22). The fix covers absolute paths, .. traversal, fsspec chained URLs (zip://…::…) and symlink escapes.
Hugging Face · peft — #3503
LoRA+'s loraplus_lr_embedding had been a silent no-op since 2024: the code resolved a parameter where it needed the owning module, so the embedding parameter group was always empty and embedding LoRA weights trained at the base learning rate, missing the B-matrix boost that LoRA+ exists to provide.
Hugging Face · sentence-transformers — #3880
In AdaptiveLayerLoss, the KL-divergence teacher was never detached, so gradients flowed back into the final layer — pulling the teacher toward the students. A bracketing error also scaled the per-layer loss by a factor of N².
Keras — #23375
CategoryEncoding.get_config() omitted sparse, so a model saved with sparse=True silently reloaded dense. Every sibling preprocessing layer already serialized it.
outlines — #1967
Gemini's Content.role accepts only user/model, but the adapter passed system straight through, malforming every chat with a system message. System messages are now collected — wherever they appear — and passed as system_instruction.
📝 Check out my Medium for deep-dives on ML, LLMs, and production AI.



