# Henrique Cardoso de Faria > Principal Engineer based in Viana do Castelo, Portugal. Specializing in Ruby on Rails, Elixir, and AI integration. ## About Software engineer with over a decade of experience, remote since 2014. Currently at BSPK building AI-powered features for luxury retail clienteling. Also runs HC Digital Services LLC, helping companies integrate AI into their Rails applications. Organized Euruko 2025, Europe's longest-running Ruby conference, in his hometown of Viana do Castelo. ## Skills - **Backend:** Ruby on Rails, Elixir/Phoenix, Python/Django - **AI/LLM:** Agentic systems, RAG pipelines, natural language search, structured LLM outputs (RubyLLM, OpenAI, Groq) - **Frontend:** Turbo/Stimulus (Hotwire), Vue, React, Angular - **Databases:** PostgreSQL, Elasticsearch, Redis, SQLite, MongoDB, Firestore - **Infrastructure:** AWS (S3, Lambda), Docker, Kamal, Sidekiq, RabbitMQ, MQTT - **Languages:** Portuguese (native), English (fluent) ## Experience ### BSPK — Principal Engineer (Jul 2023 – Present, Remote) Clienteling platform for top-tier luxury retail brands. Primary backend engineer building the AI layer from scratch. - **AI Assistant:** Multi-agent system using swarm architecture. Orchestrator routes to specialist sub-agents (Client Intelligence, Tasks & Calendar) with tools for querying shopper data, purchase history, and schedules. Provider-agnostic (OpenAI, Groq, local models). - **Natural Language Search:** LLM-powered system translating plain English into Elasticsearch queries for conversational client book search. - **Behavioral Analytics:** Observability pipeline — API event capture across 270+ endpoints, session materialization, daily metric rollups, behavioral profiling, funnel analysis, and sales outcome correlation. - **Shopify Integration:** Deep ownership of webhook pipeline — order syncing, customer assignment to nearest stores via geocoding, staff member resolution, data quality. - **Platform:** Led Rails upgrades through 8.1. Built PubSub system for real-time mobile updates with Elixir/Phoenix. Tech: Ruby on Rails, Elixir, Phoenix PubSub, PostgreSQL, Elasticsearch, Redis, Sidekiq, RubyLLM, AWS, Tailwind CSS ### BSPK — Senior Software Engineer (Aug 2020 – Jun 2022) First stint. Worked across the Rails API, admin interface, and data ingestion pipelines. Built the PubSub system for real-time mobile updates. ### Vic.ai — Senior Software Engineer, Elixir (Jul 2022 – Jul 2023) AI for real-time, autonomous enterprise accounting with prescriptive intelligence for financial decision-making. ### IndustryCare — Senior Software Engineer (Sep 2019 – May 2020) IoT data pipeline for manufacturing plants. Architected the MQTT message broker consumer for sensor data normalization and distribution. Built with Elixir, Phoenix, RabbitMQ, PostgreSQL. ### Neru — Senior Software Engineer (Jul 2018 – Sep 2019) Payment mobile application. Co-built the first shipped version, then led the growing team. Architected multi-provider payment API abstraction layer (Iugu, Zoop, Wirecard, GetNet). Built with Elixir, Phoenix, Firebase, NativeScript. ### Not In California / ActionNetwork — Software Engineer (Sep 2014 – Dec 2018) Progressive movement platform. Built events, fundraising, forms, search, and background processing systems. Ruby on Rails, MySQL, Redis, Sidekiq, Elasticsearch. ### Negócio Simples — Software Engineer (Apr 2016 – May 2018) Accounting SaaS. Architected Elixir/Phoenix API with Angular frontend for business owners and accountants. ## Community - **Euruko 2025 Organizer** — Organized Europe's longest-running Ruby conference in Viana do Castelo, Portugal. [2025.euruko.org](https://2025.euruko.org) - **hencf.org** — Open source personal website built with Rails 8.1, featuring an AI chat agent powered by RubyLLM and Groq. [github.com/henriquecf/site](https://github.com/henriquecf/site) - **Open Source** — Contributor to ja_serializer, ruby-conferences.github.io, euruko.org, and other community projects. ## HC Digital Services LLC Rails & AI consulting. Helping companies build and improve software — from Rails applications to AI integrations. Services include: - **AI Integration:** Agentic systems, natural language search, structured LLM outputs, RAG pipelines - **Rails Development:** Full-stack Rails — new features, API design, performance, upgrades, refactoring - **System Architecture:** Data pipelines, Elasticsearch, background processing, real-time systems, third-party API integrations ## Education Universidade Federal de Goiás — Software Engineering, Web Development (2012 – 2018) ## Contact - Email: elo.henrique@gmail.com - GitHub: [henriquecf](https://github.com/henriquecf) - LinkedIn: [henriquecardosodefaria](https://www.linkedin.com/in/henriquecardosodefaria) ## Blog Posts - [I Blamed the Ruby Upgrade](https://hencf.org/blog/i-blamed-the-ruby-upgrade): I bumped a Rails app to Ruby 4.0.1 and CI went red on five tests, intermittently, never on my laptop. The obvious villain was the upgrade sitting at the top of the diff. It was a red herring. The tests had always been wrong: they compared a Ruby timestamp held in memory (nanoseconds) against the same value reloaded from Postgres (microseconds), and the rounding disagreed about 1% of the time. They passed for years because I develop on macOS and CI runs on Linux, which hands out sub-microsecond timestamps far more often. The fix was one word: reload before you capture. - [SQLite in Production: The 124 GB WAL File](https://hencf.org/blog/sqlite-124gb-wal-file): My server hit 93% disk. The culprit was a 124 GB SQLite write-ahead log next to a 16 GB database, owned by my performance monitoring gem. Every safeguard against unbounded growth was switched on, and that was the problem: if the WAL never checkpoints, retention, row caps, and auto_vacuum all quietly feed it. Here's the WAL checkpoint mechanics, why a long-lived connection pins it forever, and why I removed the monitoring tool instead of fixing it. - [Off Heroku: The Playbook](https://hencf.org/blog/off-heroku-the-playbook): The technical companion to the agentic-engineering story. Kamal, Terraform, 1Password for secrets, Caddy in front of kamal-proxy, the cutover playbook, and the bugs I spent the most time on. - [I Migrated BSPK Off Heroku in Two and a Half Months. I Barely Typed.](https://hencf.org/blog/i-migrated-bspk-off-heroku): Two and a half months mostly solo. BSPK off Heroku to AWS, no downtime, 60%+ cost down. I barely wrote code. What 'agentic engineering' looks like at production scale. - [I Built an LLM Wiki for My Kid](https://hencf.org/blog/llm-wiki-for-my-kid): After building a wiki from 600 spiritist books, I built a second one from a few dozen YouTube videos, articles, and tweets about a Toy Story fan theory. The end product wasn't a website. It was a children's book for my kid. - [Turbo Ate My Redirect](https://hencf.org/blog/turbo-ate-my-redirect): A customer clicked a Stripe Connect button in my Rails app and nothing happened. Solid Errors showed RecordNotUnique exceptions from them clicking again and creating duplicate rows. The original click wasn't logged anywhere because nothing went wrong on the server. The redirect to Stripe was leaving my server fine. Turbo Drive was silently eating it, because fetch can't follow cross-origin redirects. Three things had to line up for the bug to exist. Remove any one and it goes away. - [From RAG to Wiki: What 600 Books Taught Me About Knowledge Compilation](https://hencf.org/blog/karpathy-llm-wiki-claude-code): Karpathy posted his LLM Wiki gist and I had 600 books already chunked for a RAG system. I pointed Claude Code at them to test the wiki approach instead. Six days later: 679 interlinked pages, 6,000+ cross-references, and concept pages synthesizing 36+ sources each. The first attempt was garbage because Claude skimmed instead of reading. The fix was expensive: read every chunk of every book. But the result compounds in a way RAG never will. - [I Rewrote My Rails App in Elixir. AI Brought Me Back.](https://hencf.org/blog/elixir-rewrite-ai-brought-me-back): I had a Rails side project and decided to rewrite it in Elixir/Phoenix. Streaming LLM responses, concurrency, personal interest. Built the whole thing, shared the same PostgreSQL database between both apps. Then came back to Rails. Not because Elixir was bad, but because writing code with Claude Code was a noticeably worse experience in Elixir than in Ruby. More errors, more iteration rounds, slower path to working software. When AI writes most of your code, that gap compounds fast. - [Extracting Metadata from 40K Videos with Local LLMs](https://hencf.org/blog/extracting-metadata-local-llms): I needed to extract speakers and topics from 40K+ YouTube videos for a spiritist knowledge base. Started with Groq's free tier, hit every rate limit, discovered my exception handling was silently flooding Solid Queue with 18K duplicate jobs, then moved to local models on Ollama. Along the way I found that Qwen3's default thinking mode turns a sub-second extraction into a 100-second one, and that 4B models need JSON sanitization to be reliable. - [SQLite Backups: The Boring Way](https://hencf.org/blog/sqlite-backups-the-boring-way): I spent three weeks tuning Litestream for Backblaze B2's free tier, wrote a blog post about it, then ripped the whole thing out and replaced it with a cron job. Meanwhile, my earlier SQLite auto_vacuum post led to a Rails PR that changes the default for every new SQLite database. - [I Built Search with LIKE Queries and It's Fine](https://hencf.org/blog/search-without-elasticsearch): I needed search across ten models in a multi-tenant Rails app on SQLite. Instead of Elasticsearch or FTS5, I used a denormalized table with LIKE queries and ActiveSupport's transliterate for accent-insensitive Portuguese. It took a fraction of the setup time and handles everything the app needs. - [YouTube Blocked My Server in 15 Seconds](https://hencf.org/blog/youtube-blocks-your-server): I deployed a background job to fetch transcripts from 6,000 YouTube videos. Within 15 seconds, YouTube IP-banned the server. Every approach I tried — different endpoints, different client contexts — failed from a datacenter IP. The fix was inverting the architecture: make the server an API and let a local machine do the fetching. - [Litestream and Backblaze B2's Free Tier](https://hencf.org/blog/litestream-backblaze-b2-free-tier): Litestream's default configuration generates thousands of API calls per day that silently exceed Backblaze B2's free tier. Once you hit the cap, B2 returns 403 errors, and Litestream retries without backoff, creating a spiral that stops your backups entirely. Here's how to configure it properly. - [SQLite in Production: The Disk Space Trap](https://hencf.org/blog/sqlite-auto-vacuum-rails): SQLite's default auto_vacuum is OFF. Delete a million rows and your database file stays the same size. If you're running Solid Cache, Solid Queue, or any other churn-heavy table on SQLite in production, your disk is filling up and you probably don't know it. - [Parallel Testing with Elasticsearch in Rails](https://hencf.org/blog/parallel-testing-elasticsearch-rails): Twelve parallel test workers, one shared Elasticsearch cluster. Per-worker index prefixes, a clean-room fixture company, safe_reindex without deletes, and the parallelize(workers: 1) trap that cost me three days. - [Designing Fixtures for Real Rails Apps](https://hencf.org/blog/fixtures-for-real-rails-apps): Fixtures have a bad reputation because most fixture setups are terrible. Here's how I designed YAML fixtures for a multi-tenant Rails app with complex associations, and why the result is faster, simpler, and more reliable than FactoryBot. - [RSpec to Minitest: Migrating a Large Rails App in 5 Days](https://hencf.org/blog/rspec-to-minitest-migration): After eight years on RSpec with FactoryBot, I migrated BSPK's entire test suite to Minitest with fixtures. Seventeen phases, five days, and a 5x speedup in CI. Here's the full story. - [Fetching YouTube Transcripts in Ruby](https://hencf.org/blog/youtube-transcripts-ruby): I needed captions from thousands of public YouTube videos for a knowledge base. The official API doesn't cover this use case, but YouTube's InnerTube player API does. Here's the full Ruby implementation using the same approach as youtube-transcript-api and Ruby Events, with no external dependencies. - [What Breaks When You Run an LLM 6,000 Times](https://hencf.org/blog/llm-extraction-at-scale): Extracting metadata from one video with an LLM is trivial. Doing it across 6,383 videos means debugging silent schema failures, deduplicating speakers with fuzzy matching, and building a seed pipeline to ship results from dev to production. Here's the full architecture in Rails with RubyLLM and Groq. - [RAG Without Leaving Rails](https://hencf.org/blog/rag-without-leaving-rails): Most RAG tutorials assume Python, LangChain, and Pinecone. I built a complete retrieval-augmented generation pipeline in Rails with pgvector, Ollama for local embeddings, and RubyLLM for chat. Here's the architecture and the code. - [Your Rails Images Are Slower Than You Think](https://hencf.org/blog/active-storage-image-pipeline): Active Storage defaults optimize for 'it works,' not 'it performs.' Three fixes that took an afternoon: WebP variants via a centralized helper, proxy mode for year-long caching with Thruster, and a ValidatesImageAttachment concern for upload validation. - [From rails new to 3D Printing in a Weekend](https://hencf.org/blog/rails-new-to-3d-printing-weekend): How I built a complete Hour of Code platform in three days with Claude Code: a tag designer that generates 3D-printable files in pure Ruby, a block-based coding game in Stimulus, a debugging activity, and classroom session management. Seven commits, no Node.js. - [Dynamic OG Images in Ruby with ruby-vips](https://hencf.org/blog/dynamic-og-images-ruby-vips): How I built server-side social preview images for a multi-tenant Rails app using ruby-vips: gradient backgrounds from pixel math, Pango text rendering, per-org theming, and aggressive caching. No Node.js, no headless browser, no external service. - [Web Push Notifications in Rails from Scratch](https://hencf.org/blog/web-push-notifications-rails): Building browser push notifications in a Rails app without any third-party service: VAPID keys, service workers, Stimulus controllers, recurring Solid Queue reminders, and every browser gotcha along the way. - [Extending Claude Code with Hooks, Commands, and Skills](https://hencf.org/blog/claude-code-hooks-commands-skills): How I use Claude Code's extensibility layer to catch N+1 queries at edit time, review PRs with parallel agents, and validate deployments with hooks, commands, and skills. - [Wizard to Checklist: A Stripe-Style Onboarding Pattern in Rails](https://hencf.org/blog/wizard-to-checklist-rails): How I replaced a 5-step blocking onboarding wizard with a SetupGuide PORO using Data.define, inspired by how Stripe and Linear handle user onboarding. - [A Slack Bot That Answers Questions About Your Codebase](https://hencf.org/blog/slack-bot-codebase-questions): How I built an Elixir app that connects Slack to Claude Code CLI, letting anyone on the team ask questions about the BSPK codebase and get answers sourced from the actual code. - [Multiplexing Claude Code: Parallel AI Sessions with Git Worktrees](https://hencf.org/blog/parallel-claude-code-git-worktrees): How I run four simultaneous Claude Code sessions on the same codebase using git worktrees, and what that looks like in practice on a large Rails app. - [Multi-Tenant SSL Without Cloudflare: Caddy On-Demand TLS with Kamal 2](https://hencf.org/blog/multi-tenant-ssl-caddy-kamal): How we replaced Cloudflare with Caddy's on-demand TLS to auto-issue SSL certificates for hundreds of dynamic tenant domains, validated against the Rails database. - [Building an AI Chat Agent with RubyLLM and Groq](https://hencf.org/blog/building-ai-agent-ruby-llm-groq): How I built an AI chat agent for my personal site using RubyLLM, Groq, and Turbo Streams — no RAG, no vector DB, just Rails and three tool classes. - [From Autocomplete to Autonomy: How Claude Code Changed the Way I Build Software](https://hencf.org/blog/from-autocomplete-to-autonomy): How I went from GitHub Copilot to Cursor to Claude Code, and why AI-directed development changed not just my speed but how I think about building software.