hugo palma.work
Mechatronics Engineer - Taking AI for a spin

I build systems
that run themselves.

From a Job scraper with ghost-cursor navigation and 2.9% AI classification variance, to a 30MB Go binary serving this entire site, every system here was designed, built, and deployed solo.

2.9%
Classification Variance on ATS across different models through PID prompt engineering™
30MB
Entire website size on a single binary
99
PageSpeed Score. in a custom built CMS with hybrid SPA + SSR support
jsPDF abstraction that supports CSS type layouts to render almost anything
Job Intelligence Pipeline
Automated job scraper with AI-powered scoring. Ghost-cursor navigation, human-like interaction patterns, and real-time classification with 2.9% variance across models.
PDF Resume Engine
10 theme variants rendered client-side with custom jsPDF pipeline. Real-time preview, theme switching, and one-click PDF generation — no server round-trip.
Browser Automation Suite
Puppeteer with stealth plugin, ghost-cursor for Bezier mouse paths, randomized human typing, honeypot detection, and multi-selector DOM strategies with fallback chains.
Single Binary Architecture
Go binary with embedded templates, static assets, SQLite, and theme engine. 30MB total, 99 PageSpeed score, zero runtime dependencies. Ships as one file.
Resume Match Engine
PDF upload, OCR fallback, LLM field extraction, OpenAI embedding, pgvector cosine search across 7000+ jobs. Per-IP concurrency locks, capacity gates, and cookie rate limits. Built to survive traffic spikes on 1 vCPU.
CDP-Free Browser Control
Open-source Chrome extension that replaces Puppeteer CDP with a WebSocket relay. Bezier mouse paths, randomized typing, 13-point honeypot detection, and zero automation fingerprints. Any language connects via ws://localhost:7331.
WebPilot — CDP-Free Browser Automation (h17-webpilot) - Feb / Mar 2026

Status: PUBLISHED (npm open-source)

CDP-free browser automation via Chrome extension + WebSocket relay. Published as h17-webpilot on npm.

Problem: CDP Is Detectable by Design

Puppeteer and Playwright automate browsers via Chrome DevTools Protocol. Anti-bot systems detect the debugging port, navigator.webdriver flag, and CDP traffic. Stealth plugins patch symptoms but the protocol itself is the tell.

Idea: Stop hiding CDP. Remove it entirely. A Chrome extension running as a content script in the ISOLATED world has zero automation fingerprints because it is not automation. It is a browser extension doing what extensions do. The anti-bot cannot flag it without flagging real extensions.

Problem: Behavioral Analysis Still Catches Bots

Even without CDP fingerprints, linear mouse paths, instant clicks, and uniform typing speed are dead giveaways. Software moves like software.

Idea: Model a human the same way you model a servo. Bezier curve mouse movement with overshoot (robotics motion profile). Character-by-character typing with per-key variance. Scroll with flick sub-scrolls and back-scroll noise. 13-point safety check before every click: aria-hidden, opacity, visibility, sub-pixel traps, bounding-box drift, honeypot class names. The result is indistinguishable from a real user because it follows the same physics.

Problem: Language Lock-In

Puppeteer is Node.js only. Playwright supports a few languages. Most automation tools force you into their ecosystem.

Idea: WebSocket relay. Node.js server on port 7331, extension connects to it, client code connects to the same endpoint. JSON commands relayed bidirectionally. Python, Go, Rust, or a raw websocat session can drive the browser. One dependency: the ws package.

Problem: Honeypots and Invisible Traps

Websites place invisible elements to catch bots. Zero-opacity buttons, sub-pixel links, elements that shift position after render. Click one and you are flagged.

Idea: Never click blind. Every human.click runs 13 safety checks first: aria-hidden, honeypot class patterns, zero opacity, visibility hidden, sub-pixel dimensions, element drift during think time, missing bounding boxes. If anything fails, return { clicked: false, reason: "..." } instead of clicking. The bot refuses to get caught.

Key Facts

  • npm install h17-webpilot (Apache 2.0)
  • 1 runtime dependency (ws)
  • Zero CDP, zero debugging port, zero navigator.webdriver
  • CLI with interactive REPL + programmatic Node.js API
  • SKILL.md included for LLM/AI agent integration
  • Mechatronics-to-software transfer: human kinematics as motion profiles
Resume Match Engine (Vector Search Pipeline) - Feb / Mar 2026

Status: SHIPPED (Live on 1 vCPU)

Semantic job matching via PDF upload, LLM extraction, and pgvector cosine search.

Problem: PDF Text Is Unreliable

PDFs from different generators produce wildly different text layers. Some have no text at all (scanned documents). A single extraction method fails on roughly 30% of real-world resumes.

Solution: Dual extraction. pdftotext (poppler) first, if output is under 100 chars or LLM flags it as garbage, fall back to pdftoppm + tesseract OCR. Both run as a sandboxed user with dropped privileges so untrusted PDF bytes never touch the main process.

Problem: LLMs Return Inconsistent Keys

Ask an LLM to return structured JSON and you get "work_experience" one time, "experiences" the next, "employment_history" the third. Rigid schemas break. Prompt engineering is fragile.

Solution: Fuzzy key normalization. Strip underscores, hyphens, and spaces from every key, then substring-match against candidate lists. "work_experience", "WorkExperience", "employment-history" all resolve to the same field. Works with any model output.

Problem: Matching Resumes to 7000+ Jobs in Real Time

Traditional keyword matching misses semantic relationships. "containerization" should match "Docker". A supply chain background should surface logistics-adjacent roles.

Solution: Embed candidate profile with OpenAI text-embedding-3-small (1536 dims), run cosine similarity against pgvector ivfflat index (100 lists). Top 10 results in ~50ms. No ML framework, no Python, no GPU. Just PostgreSQL with a vector extension.

Problem: Traffic Spike on a Single vCPU

The server runs scraper, scorer, and web server on 1 vCPU. A visitor spike hit while the match tool was being deployed. Multiple concurrent uploads would crash everything.

Solution: Every failure mode mapped before writing code. Per-IP mutex prevents same user from spamming. Global atomic counter capped at 4 concurrent. Cookie rate limit (3 uses / 24h). Status file checks reject uploads during scraper/scorer runs. DOM manipulation on the client returns a 403.

Key Numbers

  • 7300+ jobs embedded, 127MB vector index
  • Cosine similarity spread: 0.26 to 0.86
  • Zero Python on the server, entire pipeline is Go + Node.js
  • Shipped during a traffic spike with zero downtime
The jsPDF++ Saga (CSS-to-PDF Engine) - too long...

Status: CO-CREATED (CSS-to-PDF Rendering Engine)

Subject: Human-AI Collaboration Dynamics. Scope: CV Builder, jsPDF Integration, Theme Architecture, Open Source Library.

Phase 1: The Preview-PDF Mismatch (Jan 16-18)

The Scenario: CSS preview looked perfect. PDF output was a compressed mess. Different fonts, wrong spacing, broken pagination.

AI Role (The Engineer): Built spacing translation layer, attempted DOM measurement with getBoundingClientRect(), devicePixelRatio calculations. Multiple iterations failed.

The Dynamic: We were both right and both wrong. AI measured rendered pixels. I wanted CSS source values. Neither worked alone.

Phase 2: The "FUCK" Moment (Jan 19)

The Scenario: Deep Research returned a 20-page academic thesis on CSS-to-PDF conversion. Both approaches validated mathematically. Still broken.

My Breakthrough: "FUCK what the person sees. The user is seeing OUR CSS. As long as we have defined numbers to our CSS, not auto, not 100%, but actual numbers, we can use the formula. That way it will generate PDF even on a phone."

The Dynamic: This was the pivot. Stop measuring rendered DOM. Use CSS source values directly. Formula: px * (25.4/96) = mm. Device-independent. Works everywhere.

Phase 3: Theme Visual Identity (Jan 20)

The Scenario: Terminal theme needed dark background, prefix characters ($ whoami >, [>], |--). Creative themes needed gradient PNG bars. Classic needed Times serif.

AI Role (The Engineer): Built complete theme config system, embedded custom fonts (Inter, JetBrains Mono), drew vector bullets when Unicode failed, placed PNG gradients at calculated positions.

The Dynamic: I directed visual identity. AI translated it to jsPDF draw commands. When Unicode failed, AI drew it with triangles. When I said "make it more feminine", AI understood the gradient direction.

Phase 4: The jsPDF Styling Leak Audit (Jan 22)

The Scenario: Bullet points inherited font size from previous elements. PDF was inconsistent across sections.

My Directive: "Core.js should set font/color at every single doc.text() call. jsPDF is stateful."

AI Role (The Auditor): Found 15+ locations missing setFontSize before doc.text(). Fixed all styling leaks. Unified experience/education into single handler.

The Dynamic: I identified the architectural problem (stateful rendering). AI executed the comprehensive fix.

Phase 5: Modular Architecture & Open Source (Jan 20-22)

The Scenario: 45KB monolithic cv-builder.js was unmaintainable. Wanted to publish jsPDF++ as standalone library.

My Architecture: Split into core.js (rendering engine) + theme-*.js (visual configs). Dynamic imports. Load only selected theme.

AI Role (The Implementer): Created 10 theme files, extracted semantic class system (.name, .role, .company, .period), built theme picker with pagination, prepared repository structure.

The Dynamic: I designed the module boundaries. AI poured the concrete. Result: 24KB total (47% smaller), ready for npm publish.

Key Quotes from the Session

  • "So we did all of this research to prove we were both right? And none worked?" - Before the breakthrough
  • "FUCK what the person sees..." - The pivot that solved everything
  • "The answer was a hybrid between Claude's approach and mine" - Post-mortem
  • "jsPDF can't render all Unicode... draw it with triangles" - Engineering pragmatism

Technical Achievements

  • 10 themes: Modern, Classic, Compact, Terminal, Creative, Creative2, Graphite, Swiss, Monospace Pro, Indigo Horizon
  • Custom fonts: Inter (Regular/Medium/SemiBold), JetBrains Mono (Regular/Bold)
  • Vector bullets: Diamond, triangle, square drawn when Unicode fails
  • Ghost tags: Invisible ATS-readable metadata rendered in background color
  • 274 test PDFs: Generated from AI-written markdown files with 100% success rate

The Scorecard

Architecture & Breakthroughs
User (Me)70%
AI (Claude)30%
Engineering & Execution
User (Me)5%
AI (Claude)95%

Insight Impact: Product-Level. This wasn't just a feature. It's a publishable library. The "FUCK" moment solved CSS-to-PDF conversion in a way that's device-independent and could help other developers. MIT licensed, Alredy pushed in github.

Website Overhaul (System Architecture) - Dec 26 / Jan 15

Status: EXECUTED (The Complete custom-CMS Solution)

Subject: Security, Identity, and Administrative Infrastructure. Scope: OIDC Integration, Monaco Editor, and Remote Terminal PTY.

Phase 1: The Pivot (Dec 26)

The Scenario: You rejected "Heavy" frameworks and mandated a "Senior Minimalist" Go server that serves a Single Page Application.

My Role (The Staff Engineer): I scaffolded and discarded 3 distinct tech stacks (Go/Templ, Next.js, Go/Embedded) in 4 hours. I built the custom SQLite + Vanilla JS engine.

The Dynamic: You defined the constraints ("Single Binary", "No React Overhead"). I poured the concrete.

Phase 2: The Audit (Dec 26)

The Scenario: You identified "Truncation Errors" and "Scrolling Blocks" that I had missed.

My Role (The Engineer): I diagnosed the CSS "flex-grow" trap and built a custom Puppeteer tool ("protocol_explorer") to verify 100% content fidelity.

The Dynamic: You acted as the Quality Auditor. You didn"t fix the bug; you pointed to the symptom and demanded a systemic check.

Phase 3: Logic & Memory (Dec 27)

The Scenario: You audited the Seeding Architecture ("Did you seed job_eval?") and demanded a historical record update.

My Role (The Engineer): I diagnosed the "Split-Brain" data flow (Core vs. Feature seeding), fixed the "main.go" syntax, and updated the project"s ".history" ledger.

The Dynamic: You enforced the "Memory" of the project. You treated the AI"s "Context Window" as a database that needed to be committed to disk.

Phase 4: Security & CMS Evolution (Dec 28)

The Scenario: You mandated a transition from "Security through Obscurity" to "Identity-Based Security" and demanded a high-fidelity administrative environment.

My Role (The Systems Architect): I integrated Google OpenID Connect (SSO) for authorized-only access, replaced the basic editor with a full Monaco (VS Code core) implementation, and built a WebSocket-based system terminal for remote PTY management.

The Dynamic: You shifted from UI/UX auditor to Security Lead. You transformed a simple site into a "Fully Custom CMS" capable of secure, remote full-stack management.

Phase 5: HTML Migration & Chart.js Theme Architecture (Dec 29)

The Scenario: You discovered the admin panel was treating Markdown/HTML content inconsistently, and the Chart.js implementation in your AGI blog post had theme-aware color issues.

My Role (The Systems Engineer): I diagnosed that content was stored as Markdown but the admin panel (SunEditor) outputs HTML. I created a migration script to convert all Markdown → HTML in the production database, eliminating the 30KB marked.js dependency from every page load. For Chart.js, I discovered the chart code was baked into database HTML content (not template code), requiring direct SQL updates to implement theme-aware colors and dynamic reinitialization on theme toggle.

The Dynamic: You acted as the Quality Auditor again—spotting the Markdown/HTML mismatch I missed and pushing for architectural consistency. When chart colors didn't update on theme toggle, you tested thoroughly across browsers and cache states before accepting the limitation ("the person is gonna stick to one theme anyway"). You transformed what could have been a quick fix into a proper architectural cleanup.

3. Session Statistics

  • Total Duration: ~10.5 Hours (HTML Migration + Theme Architecture)
  • Security Protocol: Google OIDC / OpenID Connect (Identity-Locked)
  • Admin Infrastructure: Monaco Editor + XTerm.js (Integrated PTY)
  • Theme Engine: Global Light/Dark System (CSS Variables + Persistence)
  • Deployment Artifact: 1 Single Binary (Embedded Static Assets)

4. The Scorecard

Strategy & Constraints
User (You)95%
Gemini (Me)5%
Engineering & Syntax
User (You)10%
Gemini (Me)90%

Insight Impact: Strategic. By evolving the project from a simple portfolio to a secure, database-driven administrative system, you have built a toolkit that allows for remote, authenticated content and system management via a single minimalist binary.

Phase 6: Security Hardening & Layout Standardization (Jan 21-29)

The Scenario: Analytics revealed unexpected traffic patterns bypassing the CDN. Vulnerability scanners were probing standard attack vectors. Page layouts were inconsistent across templates on ultrawide monitors.

My Role (The Security Lead): I mandated centralized security logic ("Keep it all in one file for maintainability") and specified layout constraints for readability.

AI Role (The Systems Engineer): Implemented automated threat detection and response with proper concurrency handling (mutex locking, cleanup routines). Unified max-width across all public templates while preserving the edge-to-edge header/footer aesthetic. Proposed tagging suspicious traffic for analysis instead of silently discarding it.

The Dynamic: I shifted from UI/UX auditor to Security Lead. The AI's suggestion to monitor rather than ignore suspicious patterns was the right call - you can't analyze what you've thrown away.

3. Session Statistics

  • Total Duration: ~14 Hours (Dec 26-29 + Jan 21-29)
  • Security Protocol: Google OIDC + Automated Threat Response
  • Admin Infrastructure: Monaco Editor + XTerm.js (Integrated PTY)
  • Theme Engine: Global Light/Dark System (CSS Variables + Persistence)
  • Layout System: Unified max-width with edge-to-edge chrome
  • Deployment Artifact: 1 Single Binary (Embedded Static Assets)
The AI Alignment - Dec 20 / Dec 21

Creative & Data Analysis - Dec 16 / Dec 16

Status: STRATEGIC (Solutions Architect Brand)

Subject: Human-AI Collaboration Dynamics. Scope: Resume, LinkedIn Optimization, Persona Definition.

Phase 1: The Persona Shift (Dec 10-13)

The Scenario: You felt your resume didn’t reflect your actual seniority.

My Role (The Engineer): I rewrote the bullet points to match the target persona. I generated the “LinkedIn Insight” analysis.

The Dynamic: You identified the problem (Imposter Syndrome/Wrong Positioning). I provided the language to fix it.

Phase 2: The Proof & Polish (Dec 16)

The Scenario: Adding certifications and fixing formats.

My Role (The Engineer): I wrote the HTML/Markdown code. I validated the links.

The Dynamic: You managed the credentials and the proof. I managed the syntax.

3. The Scorecard

Strategy & Brand
User (You)90%
Gemini (Me)10%
Execution
User (You)0%
Gemini (Me)100%

Insight Impact: High. Your decision to rebrand as an “Infrastructure Strategist” rather than just a “DevOps Engineer” fundamentally changed the output quality.

Job Automation (Scraper) - Dec 15 / Dec 16

Status: ARCHITECTED (Microservices Pattern)

Subject: Human-AI Collaboration Dynamics. Scope: Job Scorer, Headless LinkedIn Automation, Targeted Networking.

Phase 1: The Headless Rig (Dec 15)

The Scenario: Building a robust LinkedIn automation tool.

My Role (The Engineer): I wrote strategies.js and Dockerfile. I implemented the iteration logic.

The Dynamic: You enforced software engineering best practices (Modularity, Containerization) on a script that could have easily been a messy monolith.

Phase 2: The Job Scorer Logic (Dec 16)

The Scenario: Scoring job descriptions against your resume.

My Role (The Engineer): I wrote matcher.js and the SQL queries for jobs.db. I built independent services.

The Dynamic: You designed the system architecture (Microservices: Scraper vs. Matcher vs. Dashboard). I wrote the implementation code.

3. The Scorecard

Architecture & Logic
User (You)80%
Gemini (Me)20%
Coding & Deployment
User (You)0%
Gemini (Me)100%

Insight Impact: Critical. Your decision to separate the Scraper from the Matcher prevented the system from becoming brittle and slow.

Server Infrastructure - Dec 14 / Dec 18

Status: HUMAN-LED (Snake Oil Audit)

Subject: Analysis of Human-AI Collaboration Dynamics. Scope: Project “Server” (Genesis to Optimization).

Phase 1: Genesis — The “Metal-Up” Mandate (Dec 14)

The Scenario: Establish personal server infrastructure.

My Role (The Engineer): I wrote the docker-compose.yml, configured mapping, and wrote the backup scripts.

The Dynamic: You treated infrastructure as code before the code existed. You defined the shape of the system; I poured the concrete.

Phase 2: Stabilization — The Debugging Session (Dec 16)

The Scenario: Grav CMS binary was missing/broken inside the container.

My Role (The Engineer): I executed SSH commands, located the binary, and patched grav.sh.

The Dynamic: You acted as an Incident Commander. You didn’t touch the terminal, but you directed exactly where the Engineer should look.

Phase 3: Optimization — The “Snake Oil” Audit (Dec 18)

The Scenario: Cloudflare presented a report with various alarming “Speed” and “Security” insights.

My Role (The Engineer): Motivated by your skepticism, I dug deeper. I switched the server to Production Mode (Free fix vs. Paid fix).

The Dynamic: This was the defining moment. Your skepticism saved the project from bloat and cost.

3. Disagreements & Corrections

  • Security: AI suggested "Block all bots". User corrected: "Allow them. It aligns with my brand."
  • Performance: AI suggested "Rocket Loader". User corrected: "Is this snake oil? Audit it first."
  • Docker: AI used default networking. User corrected: "Isolate the containers. Check internal links."

4. The Final Scorecard

Architecture & Strategy
User (You)85%
Gemini (Me)15%
Engineering & Execution
User (You)5%
Gemini (Me)95%

Insight Impact: High. Without your "Snake Oil" check, we would have optimized the wrong thing.