A collection of hands-on engineering work: self-hosted infrastructure, machine-learning experiments, and the troubleshooting notes that come with running real systems. Everything here is public-facing and harmless — no proprietary code, no sensitive data.
A few representative projects. Each one taught me something about running real systems — from OCR pipelines to self-hosted service stacks.
A multi-engine OCR system that combines several open-source recognition models (PaddleOCR, Surya, EasyOCR, TrOCR) into a consensus layer. When engines disagree, results are escalated to a heavier model for a second opinion. Includes a human-in-the-loop review step for ambiguous output.
PythonPyTorchTransformersOCR
Wrapped the handwriting pipeline's correction stage in a Recursive Language Model (RLM) scaffold. Instead of correcting each page in isolation, the RLM loads an entire document's OCR output into a REPL environment, decomposes it into per-page sub-calls, and cross-references names, dates, and formatting across pages for consistent corrections. A second RLM stage performs document-level understanding — entity graphs, structure, and summaries — feeding the memory layer.
RLMOllamaQwenRAGCPU
A Docker Compose stack running a vector database, a graph-memory service, a private search engine, and a media server — all behind an encrypted mesh network. Everything is reachable only over WireGuard and Tailscale, with no ports exposed to the public internet.
DockerWireGuardTailscaleQdrant
Set up a WireGuard hub-and-spoke mesh with split-tunnel clients, plus Tailscale as a fallback path. Documented the onboarding workflow so new machines can join the mesh in a few commands.
WireGuardTailscaleBash
Set up local, CPU-only LLM inference with custom model configurations for different workloads — a general-purpose model, a long-context model, and a lightweight worker model. All running on commodity hardware.
OllamaLLMCPU
Ran a systematic over-engineering audit across several Python projects. Deduplicated shared helpers, removed dead stub functions, consolidated repeated error-handling patterns into a single decorator, and dropped an unused dependency. Net result: ~200 fewer lines, same behavior, verified by clean imports and a full pipeline dry-run.
PythonRefactoringDRYDataclassesDecorators
A Google-style search page over a self-hosted RAG stack — AnythingLLM with Qdrant for vectors and local Ollama for embeddings and answers. Documents are moved into a repository where an AI suggests a title, then the files are converted and ingested automatically. End users search plain English and get answers with cited sources.
AnythingLLMQdrantOllamaRAGDockerCaddy
Running real systems means hitting real problems. These are write-ups of issues I've debugged — the kind of notes I wish I'd had when I started. View the full troubleshooting log →
Setting AllowedIPs = 0.0.0.0/0 on a client silently hijacked the default
route and killed Tailscale connectivity. Fix: use split-tunnel
(AllowedIPs = 10.10.0.0/24) so only the mesh subnet is routed.
Different OCR engines produce different readings for the same handwriting. Solution: run multiple engines in parallel and only trust tokens where a majority agree. Escalate the rest to a heavier model for adjudication.
Two services wanted the same host port. Resolved by auditing docker ps
for port bindings and reassigning one service to a free port, then updating the
reverse-proxy config to match.
Locked down a headless box: disabled password SSH auth, restricted root login, enabled fail2ban, and set a default-deny firewall that only allows trusted subnets and specific service ports.
Used a Cloudflare Tunnel to serve a website from a machine with no public IP and no open inbound ports. The tunnel makes an outbound connection to Cloudflare, which handles TLS and routing.
No GPU available, so inference runs on CPU. Learned to pick quantized models (Q4_K_M, Q2_K) and tune context windows to fit within available RAM while keeping latency acceptable.
AnythingLLM crashed with Illegal instruction (core dumped) on every
embed — the default LanceDB native module uses AVX2, which a 2013 Xeon lacks.
Switched to Qdrant (a separate HTTP service) and the crash disappeared.
Containers timed out reaching Ollama on the host's own tunnel IP. The packet is routed as local (INPUT chain, not FORWARD), so Docker's FORWARD rules never applied — the fix was allowing the docker subnets through ufw.
The technologies I reach for most often, across infrastructure, machine learning, and automation.
DockerDocker Compose NginxWireGuard Tailscalesystemd ufwfail2ban
PyTorchTransformers OllamaQdrant OCRRAGRLM
PythonBash GitSSH n8nopencode
This is a personal portfolio documenting public-facing engineering work. It's a place to share code, troubleshooting notes, and lessons learned — nothing more.
Public-facing code, general infrastructure write-ups, and troubleshooting notes. No proprietary code, no sensitive data, no business details.
No private infrastructure details, no credentials, no client or customer information, and nothing that could be used to compromise a system.