🔭 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.
14 merged fixes across 11 repositories · 510k+ 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 · #52529 batched echo prepended the user's prompt to the assistant reply |
| 🔺 | OpenAI · triton 20k★ |
#11602 autotuner silently ignored unknown key names, so kernels never re-tuned |
| 🧠 | 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 →
OpenAI · triton — #11602
key, reset_to_zero and restore_value are documented as lists of kernel argument names, but a name that wasn't one was silently dropped when the tuning key was built — so a stale or misspelled entry left the kernel autotuning once and reusing that config no matter how the real argument changed. No error, no warning; the only symptom was a kernel that quietly stopped re-tuning. An AST scan of the repository found the footgun live in Triton's own test suite. The fix validates the three name lists up front, and also initializes restore_copies, which was unset whenever a user-supplied pre_hook was combined with restore_value.
vLLM — #52528, #52529
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.
In batched chat completions, echo=True prepended the user's own prompt to the assistant's reply whenever add_generation_prompt was set (the default): the code took the last conversation turn's content without checking its role. The non-batched path guards this in both its streaming and non-streaming branches; the batch path was the only one missing it. Fixed to match, per vLLM's own documented echo semantics ("if they belong to the same role").
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.



