<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:image="http://www.google.com/schemas/sitemap-image/1.1">
  <url>
    <loc>https://omarbadran.dev/</loc>
    <lastmod>2026-08-25</lastmod>
    <changefreq>monthly</changefreq>
    <priority>1.0</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/profile-sticker.webp</image:loc>
      <image:title>Omar Badran — عمر بدران</image:title>
      <image:caption>Full-Stack developer and application security specialist in Alexandria, Egypt.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/cv</loc>
    <lastmod>2026-08-25</lastmod>
    <changefreq>monthly</changefreq>
    <priority>0.9</priority>
  </url>

  <url>
    <loc>https://omarbadran.dev/projects</loc>
    <lastmod>2026-08-25</lastmod>
    <changefreq>monthly</changefreq>
    <priority>0.9</priority>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog</loc>
    <lastmod>2026-08-15</lastmod>
    <changefreq>weekly</changefreq>
    <priority>0.8</priority>
  </url>

  <url>
    <loc>https://omarbadran.dev/projects/remas-residence</loc>
    <lastmod>2026-08-25</lastmod>
    <changefreq>monthly</changefreq>
    <priority>0.8</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/projects/remas-residence/1.webp</image:loc>
      <image:title>Remas Residences</image:title>
      <image:caption>A bilingual, Arabic-first marketing and lead site for Remas Residences — an Egyptian real-estate developer established in 2011 and based in New Borg El Arab, Alexandria. React 18 + TypeScript on Vite 6 and Tailwind 4, with a custom build-time prerenderer that writes real per-locale metadata for every route. The content model refuses to publish an unverified price, delivery date or unit count: commercial fields are optional, every project record starts non-indexable, and promotion is an explicit decision.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/projects/tulip</loc>
    <lastmod>2026-08-25</lastmod>
    <changefreq>monthly</changefreq>
    <priority>0.8</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/projects/tulip/1.webp</image:loc>
      <image:title>Tulip Flowers</image:title>
      <image:caption>A multi-location luxury flower storefront for the Egyptian market — Alexandria, New Borg Al Arab, and Alamein — each branch running as an independent store with its own pricing, availability, and imagery. Arabic RTL-first, with no payment gateway by design: checkout composes a fully-Arabic WhatsApp order message the shop owner confirms offline. React 18 + Vite + TypeScript monorepo with an Express + Prisma backend and a full admin dashboard.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/projects/avenue</loc>
    <lastmod>2026-08-25</lastmod>
    <changefreq>monthly</changefreq>
    <priority>0.8</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/projects/avenue/1.webp</image:loc>
      <image:title>Avenue Interior Design</image:title>
      <image:caption>A premium interior-design and decoration platform for a Borg El Arab company serving all of Egypt — two businesses on one site: full design/decoration services plus a deep, browsable catalog of materials and furniture organized by type, color, value tier, and style. Three-app deploy: public React SPA, staff admin dashboard, and an Express + Prisma API with email-OTP 2FA, a bookings state machine, and a Gemini AI assistant proxy with PII redaction.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/projects/sky-lens</loc>
    <lastmod>2026-08-25</lastmod>
    <changefreq>monthly</changefreq>
    <priority>0.8</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/projects/sky-lens/1.webp</image:loc>
      <image:title>SkyLens</image:title>
      <image:caption>A premium photography studio website, rebuilt and expanded — immersive gallery experience, booking system, cinematic scroll animations, and now a production backend powering content management behind the scenes. Focused on performance and visual storytelling — proof that the web can feel like cinema.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/projects/cyber-masry</loc>
    <lastmod>2026-08-25</lastmod>
    <changefreq>monthly</changefreq>
    <priority>0.8</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/projects/cyber-masry/1.webp</image:loc>
      <image:title>Cyber Masry</image:title>
      <image:caption>An Egyptian cybersecurity platform providing threat intelligence, security training, and enterprise-grade tools. Built with security-first architecture and real-time monitoring dashboards. Every endpoint hardened, every data flow encrypted — a platform born from real-world AppSec experience.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/projects/sanad</loc>
    <lastmod>2026-08-25</lastmod>
    <changefreq>monthly</changefreq>
    <priority>0.8</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/projects/sanad/1.webp</image:loc>
      <image:title>Sanad</image:title>
      <image:caption>A cybersecurity and digital solutions platform for a Saudi-based information security firm. Built with a security-first architecture to support threat protection services, IT governance, and digital transformation — serving enterprise clients across the Kingdom with a clean, professional Arabic-first interface.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/projects/ahm-construction</loc>
    <lastmod>2026-08-25</lastmod>
    <changefreq>monthly</changefreq>
    <priority>0.8</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/projects/AHM/1.webp</image:loc>
      <image:title>AHM Construction</image:title>
      <image:caption>A premium web presence for AHM للتشييد والبناء — a Kuwaiti luxury construction and engineering company. Bold visual design, a structured project showcase, and a seamless client experience that matches the caliber of their on-site engineering.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/projects/almentor</loc>
    <lastmod>2026-08-25</lastmod>
    <changefreq>monthly</changefreq>
    <priority>0.8</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/projects/almentor/1.webp</image:loc>
      <image:title>Almentor</image:title>
      <image:caption>A comprehensive e-learning platform connecting students with expert mentors. Features live sessions, course management, and progress tracking — built for scale with a clean modern interface. Designed to make world-class education accessible across the Arab world.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/projects/unit-enterprise</loc>
    <lastmod>2026-08-25</lastmod>
    <changefreq>monthly</changefreq>
    <priority>0.8</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/projects/unit-enterprise/1.webp</image:loc>
      <image:title>Unit Enterprise</image:title>
      <image:caption>A corporate enterprise platform for business management and team collaboration. Features a real-time dashboard, CRM integration, and analytics built for data-driven decisions at scale. Architecture designed for reliability under enterprise workloads.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/projects/old-portfolios</loc>
    <lastmod>2026-08-25</lastmod>
    <changefreq>monthly</changefreq>
    <priority>0.8</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/projects/old-portfolio/1.webp</image:loc>
      <image:title>Old Portfolios</image:title>
      <image:caption>Two earlier generations of this portfolio — each a snapshot of my design and development evolution. Built from scratch, each version reflects a different chapter of my journey as a full-stack developer. V3 is the loudest one yet.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/crowdsec-behavioral-blocking</loc>
    <lastmod>2026-08-15</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog-v2/crowdsec-behavioral-blocking.webp</image:loc>
      <image:title>Blocking Bad Traffic by Behaviour, Not by IP List</image:title>
      <image:caption>Read your own logs, detect the patterns that matter, and act. Plus the shared-signal model, and why you should not trust it blindly.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/opa-policy-as-code</loc>
    <lastmod>2026-08-15</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog-v2/opa-policy-as-code.webp</image:loc>
      <image:title>Authorisation Rules Belong in One Place</image:title>
      <image:caption>When 'who can do what' is scattered across handlers, no one can answer the question. Policy as code makes the rules readable, testable and reviewable.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/owasp-cheatsheets</loc>
    <lastmod>2026-08-14</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog-v2/owasp-cheatsheets.webp</image:loc>
      <image:title>The OWASP Cheat Sheets Are the Answer to Most Security Questions</image:title>
      <image:caption>Not the Top 10 — the cheat sheets. Concrete, implementation-level guidance on the things you are actually about to get wrong.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/dompurify-xss-sanitizer</loc>
    <lastmod>2026-08-14</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog-v2/dompurify-xss-sanitizer.webp</image:loc>
      <image:title>Sanitising HTML: Do Not Write Your Own</image:title>
      <image:caption>If your app renders HTML it did not write, you need a sanitiser. Regex is not a sanitiser, and the bypasses that prove it are more creative than you expect.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/markitdown-rag-ingest</loc>
    <lastmod>2026-08-13</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog-v2/markitdown-rag-ingest.webp</image:loc>
      <image:title>Your RAG Pipeline Is Only as Good as the Text You Fed It</image:title>
      <image:caption>Most retrieval failures happen at ingestion. Converting documents to clean structured markdown before chunking fixes more than any embedding model change.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/openhands-autonomous-dev</loc>
    <lastmod>2026-08-13</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog-v2/openhands-autonomous-dev.webp</image:loc>
      <image:title>Autonomous Coding Agents: Where the Line Is</image:title>
      <image:caption>An agent that plans, edits, runs and iterates on its own is impressive. The engineering question is what it is allowed to touch while it does that.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/langfuse-llm-observability</loc>
    <lastmod>2026-08-12</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog-v2/langfuse-llm-observability.webp</image:loc>
      <image:title>You Cannot Debug an LLM Feature You Cannot See</image:title>
      <image:caption>Traces, prompt versions and evaluation scores for AI features. Without them, 'it gave a bad answer' is a bug report with no reproduction steps.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/browser-use-agents</loc>
    <lastmod>2026-08-12</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog-v2/browser-use-agents.webp</image:loc>
      <image:title>Agents That Drive a Browser: Useful and Dangerous</image:title>
      <image:caption>Letting a model click through a real website solves problems no API covers. It also hands a language model your session cookies — here is how to scope that.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/claude-cookbooks-patterns</loc>
    <lastmod>2026-08-11</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog-v2/claude-cookbooks-patterns.webp</image:loc>
      <image:title>The Patterns Worth Stealing From the Claude Cookbooks</image:title>
      <image:caption>Runnable notebooks beat prose about prompting. The four patterns in there that changed how I build features on top of a model.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/litellm-gateway</loc>
    <lastmod>2026-08-11</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog-v2/litellm-gateway.webp</image:loc>
      <image:title>One Gateway in Front of Every Model</image:title>
      <image:caption>A proxy that speaks one API to your app and many APIs to providers. The value is not switching models — it is the key handling, budgets and logs you get for free.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/lucide-icon-system</loc>
    <lastmod>2026-08-10</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog-v2/lucide-icon-system.webp</image:loc>
      <image:title>Icons Are a System, Not a Folder of SVGs</image:title>
      <image:caption>Consistent stroke weight, one grid, tree-shakeable imports, and the accessibility rule that decides whether an icon should be announced at all.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/claude-code-agentic-terminal</loc>
    <lastmod>2026-08-10</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog-v2/claude-code-agentic-terminal.webp</image:loc>
      <image:title>Claude Code: What Changes When the Agent Has a Terminal</image:title>
      <image:caption>An assistant that can read the repo, run the tests and see the failure is a different tool from one that autocompletes. Here is how I actually use it, and where I do not.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/react-three-fiber-3d</loc>
    <lastmod>2026-08-09</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog-v2/react-three-fiber-3d.webp</image:loc>
      <image:title>React Three Fiber: 3D Without Leaving React</image:title>
      <image:caption>Three.js as components, with the reconciler doing the scene-graph bookkeeping. The hard part was never the code — it is deciding whether the page needs 3D at all.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/million-react-compiler</loc>
    <lastmod>2026-08-09</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog-v2/million-react-compiler.webp</image:loc>
      <image:title>Before You Reach for a Faster React</image:title>
      <image:caption>Compilers that speed up React rendering are real and clever. They also solve the second-biggest problem on most pages — here is how to find out if you have the first one.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/jotai-atomic-state</loc>
    <lastmod>2026-08-08</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog-v2/jotai-atomic-state.webp</image:loc>
      <image:title>Jotai: State That Only Wakes Who Needs It</image:title>
      <image:caption>Bottom-up atoms instead of a single store. Derived state is a computed atom, and only the components reading a changed atom re-render.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/tanstack-router-typed-routes</loc>
    <lastmod>2026-08-08</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog-v2/tanstack-router-typed-routes.webp</image:loc>
      <image:title>Type-Safe Routing: No More Guessing Params</image:title>
      <image:caption>If a route's params and search schema are typed, a broken link becomes a compile error instead of a blank page someone finds in production.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/storybook-component-contracts</loc>
    <lastmod>2026-08-07</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog-v2/storybook-component-contracts.webp</image:loc>
      <image:title>Storybook Is a Contract, Not a Gallery</image:title>
      <image:caption>The value is not the pretty component browser. It is that every state a component can be in has to be written down, and the ugly ones stop being discovered in production.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/hono-edge-api</loc>
    <lastmod>2026-08-07</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog-v2/hono-edge-api.webp</image:loc>
      <image:title>Hono: An API That Runs Anywhere</image:title>
      <image:caption>Built on Web Standards rather than Node APIs, so the same handler runs on Node, Bun, Deno, Cloudflare Workers and Lambda. Small, typed and genuinely fast.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/tailwind-v4-engine</loc>
    <lastmod>2026-08-06</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog-v2/tailwind-v4-engine.webp</image:loc>
      <image:title>Tailwind 4: The Config File Is Gone</image:title>
      <image:caption>Design tokens moved into CSS itself. That sounds cosmetic until you realise it means your theme is readable by every tool that understands a stylesheet.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/vite-build-speed</loc>
    <lastmod>2026-08-06</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog-v2/vite-build-speed.webp</image:loc>
      <image:title>Vite: Why the Dev Server Feels Instant</image:title>
      <image:caption>It does not bundle during development. Understanding that one decision explains the speed, the plugin model, and the two places it still surprises people.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/sonner-toast-ux</loc>
    <lastmod>2026-08-05</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog-v2/sonner-toast-ux.webp</image:loc>
      <image:title>Toasts Nobody Hates</image:title>
      <image:caption>Toast notifications are usually an accessibility failure with a nice animation. Getting them right is mostly about knowing when not to use one.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/shiki-syntax-highlighting</loc>
    <lastmod>2026-08-05</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog-v2/shiki-syntax-highlighting.webp</image:loc>
      <image:title>Shiki: Syntax Highlighting With Zero Runtime</image:title>
      <image:caption>Highlight code at build time with the same engine your editor uses. The visitor downloads coloured HTML instead of a highlighting library and a grammar bundle.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/dnd-kit-accessible-drag</loc>
    <lastmod>2026-08-04</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog-v2/dnd-kit-accessible-drag.webp</image:loc>
      <image:title>dnd-kit: Drag and Drop That Works Without a Mouse</image:title>
      <image:caption>Most drag-and-drop implementations are unusable by keyboard and silent to screen readers. This one ships both, and it is lighter than what it replaces.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/nuqs-url-state</loc>
    <lastmod>2026-08-04</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog-v2/nuqs-url-state.webp</image:loc>
      <image:title>Put Filter State in the URL, Not in useState</image:title>
      <image:caption>If a filtered view cannot be bookmarked, shared or reloaded, it is a bug — not a design choice. nuqs makes the URL the state, with types.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/tanstack-table-headless</loc>
    <lastmod>2026-08-03</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog-v2/tanstack-table-headless.webp</image:loc>
      <image:title>TanStack Table: Stop Rewriting Sorting and Pagination</image:title>
      <image:caption>It renders nothing. That is the point — you get sorting, filtering, grouping and pagination as logic, and the markup stays yours.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/motion-react-animation</loc>
    <lastmod>2026-08-03</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog-v2/motion-react-animation.webp</image:loc>
      <image:title>Motion: Animation That Respects the User</image:title>
      <image:caption>Declarative animation in React, layout transitions that would take an afternoon by hand, and a reduced-motion story that is one hook rather than an audit finding.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/react-hook-form-uncontrolled</loc>
    <lastmod>2026-08-02</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog-v2/react-hook-form-uncontrolled.webp</image:loc>
      <image:title>React Hook Form: Fewer Renders, Fewer Bugs</image:title>
      <image:caption>Controlled inputs re-render the form on every keystroke and give you nothing for it. Uncontrolled forms with a validation schema are faster and shorter at the same time.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/radix-primitives-a11y</loc>
    <lastmod>2026-08-02</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog-v2/radix-primitives-a11y.webp</image:loc>
      <image:title>Radix Primitives: Behaviour Without the Look</image:title>
      <image:caption>Every custom dropdown I have audited had the same six accessibility bugs. Radix ships the keyboard handling and focus management unstyled, so you keep your design and lose the bugs.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/tanstack-query-server-state</loc>
    <lastmod>2026-08-01</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog-v2/tanstack-query-server-state.webp</image:loc>
      <image:title>Stop Putting Server Data in useState</image:title>
      <image:caption>Most React state bugs are one mistake wearing different hats: treating a copy of the server's data as if you owned it. TanStack Query fixes the category, not the symptom.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/zustand-state-without-boilerplate</loc>
    <lastmod>2026-08-01</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog-v2/zustand-state-without-boilerplate.webp</image:loc>
      <image:title>Zustand: State Management You Can Read in One Sitting</image:title>
      <image:caption>A store is a hook. That is the whole idea. No providers, no actions file, no reducer ceremony — and it scales further than the ceremony did.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/ollama-local-models</loc>
    <lastmod>2026-07-28</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog/ollama-local-models.webp</image:loc>
      <image:title>Ollama: Run Real Models on Your Own Machine</image:title>
      <image:caption>One command pulls a model and serves it on localhost. For prototyping, private data, and never paying per token again.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/claude-code-skills</loc>
    <lastmod>2026-07-24</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog/claude-code-skills.webp</image:loc>
      <image:title>Turn Your Workflow Into a Claude Skill</image:title>
      <image:caption>Prompting the same instructions every session is a waste. A skill is a folder that teaches the model how you work — once — and it pays back on every project after that.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/llama-cpp-quantization</loc>
    <lastmod>2026-07-21</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog/llama-cpp-quantization.webp</image:loc>
      <image:title>llama.cpp and the Quantization You Actually Need</image:title>
      <image:caption>Q4, Q5, Q8 — the difference between a model that fits your GPU and one that does not, explained without the maths.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/subagent-team</loc>
    <lastmod>2026-07-17</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog/subagent-team.webp</image:loc>
      <image:title>Building a Subagent Team That Reviews Its Own Work</image:title>
      <image:caption>One agent writing code is autocomplete. Several specialists who critique and correct each other is a process — and the difference shows up in the diff.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/vllm-serving-throughput</loc>
    <lastmod>2026-07-14</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog/vllm-serving-throughput.webp</image:loc>
      <image:title>vLLM: When You Outgrow One Request at a Time</image:title>
      <image:caption>Continuous batching and paged attention are why a serving stack handles fifty concurrent users on hardware that choked on five.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/claude-md-that-works</loc>
    <lastmod>2026-07-09</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog/claude-md-that-works.webp</image:loc>
      <image:title>Writing a CLAUDE.md the Model Actually Follows</image:title>
      <image:caption>Most project instruction files are wish lists. The ones that work read like a senior engineer briefing a new hire on day one — specific, ordered, and short.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/open-webui-chat-ui</loc>
    <lastmod>2026-07-07</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog/open-webui-chat-ui.webp</image:loc>
      <image:title>Open WebUI: A Chat Front-End Your Client Can Actually Use</image:title>
      <image:caption>Local models are useless to a business until someone non-technical can talk to them. This is the missing half.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/portfolio-that-converts</loc>
    <lastmod>2026-06-30</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog/portfolio-that-converts.webp</image:loc>
      <image:title>Your Portfolio Is a Product, Not a Gallery</image:title>
      <image:caption>A grid of screenshots tells a client what you touched. A case study tells them what you decided — and decisions are the only thing they are actually buying.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/whisper-speech-to-text</loc>
    <lastmod>2026-06-30</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog/whisper-speech-to-text.webp</image:loc>
      <image:title>Whisper: Transcription That Handles Arabic</image:title>
      <image:caption>Most speech-to-text falls apart on Arabic dialects. Here is what actually works, and where it still struggles.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/comfyui-node-pipelines</loc>
    <lastmod>2026-06-23</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog/comfyui-node-pipelines.webp</image:loc>
      <image:title>ComfyUI: Image Generation as a Pipeline, Not a Prompt Box</image:title>
      <image:caption>Nodes and graphs look intimidating until you need the same result twice. Then they are the only sane option.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/rtl-first-arabic</loc>
    <lastmod>2026-06-21</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog/rtl-first-arabic.webp</image:loc>
      <image:title>Arabic-First, Not Arabic-Translated</image:title>
      <image:caption>Flipping a layout to RTL is twenty minutes of CSS. Making an Arabic interface feel native is a different job entirely — and users notice the gap immediately.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/aider-terminal-pair</loc>
    <lastmod>2026-06-16</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog/aider-terminal-pair.webp</image:loc>
      <image:title>Aider: AI Pair Programming That Commits</image:title>
      <image:caption>It edits your repo and writes the commit message. Which is either exactly what you want or a very good reason to work on a branch.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/own-your-name-seo</loc>
    <lastmod>2026-06-12</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog/own-your-name-seo.webp</image:loc>
      <image:title>Owning Your Own Name in Search</image:title>
      <image:caption>If someone searches your name after a meeting, whatever they find becomes your reference check. Here is the exact stack I used to make sure they find me.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/continue-dev-assistant</loc>
    <lastmod>2026-06-09</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog/continue-dev-assistant.webp</image:loc>
      <image:title>Continue: An Open-Source Coding Assistant You Control</image:title>
      <image:caption>Point it at a local model, a cloud model, or both. The value is choosing where your code goes.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/llms-txt-geo</loc>
    <lastmod>2026-06-03</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog/llms-txt-geo.webp</image:loc>
      <image:title>Getting Cited by AI Answer Engines</image:title>
      <image:caption>People ask a model about you before they open a search engine. Generative engine optimisation is mostly just being unambiguous in machine-readable ways.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/mcp-servers</loc>
    <lastmod>2026-06-02</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog/mcp-servers.webp</image:loc>
      <image:title>Model Context Protocol: Stop Writing Bespoke Tool Glue</image:title>
      <image:caption>One protocol so any assistant can talk to your database, your files, your ticketing system. Write the server once.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/whatsapp-checkout</loc>
    <lastmod>2026-05-26</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog/whatsapp-checkout.webp</image:loc>
      <image:title>When the Best Checkout Is No Checkout</image:title>
      <image:caption>I built a storefront with no payment gateway on purpose. In the right market, a well-formed WhatsApp message converts better than any card form you can design.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/langchain-when-to-use</loc>
    <lastmod>2026-05-26</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog/langchain-when-to-use.webp</image:loc>
      <image:title>LangChain: When the Framework Helps and When It Hurts</image:title>
      <image:caption>For a three-step chain, the raw SDK is shorter and clearer. For an agent with twelve tools and retries, it is not.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/llamaindex-rag</loc>
    <lastmod>2026-05-19</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog/llamaindex-rag.webp</image:loc>
      <image:title>LlamaIndex: RAG Beyond the Toy Example</image:title>
      <image:caption>Chunking strategy decides whether your retrieval works. Everything else is a distant second.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/security-by-design-small-teams</loc>
    <lastmod>2026-05-18</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog/security-by-design-small-teams.webp</image:loc>
      <image:title>Security by Design When You Are the Whole Team</image:title>
      <image:caption>You do not get a security review, a pentest budget, or a second pair of eyes. What you get is the ability to make the cheap decisions early — before they become expensive.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/qdrant-vector-search</loc>
    <lastmod>2026-05-12</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog/qdrant-vector-search.webp</image:loc>
      <image:title>Qdrant: Picking a Vector Database Without the Hype</image:title>
      <image:caption>Filtered search is the feature that decides this, not raw benchmark numbers nobody reproduces.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/llm-proxy-pii</loc>
    <lastmod>2026-05-08</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog/llm-proxy-pii.webp</image:loc>
      <image:title>Never Put Your API Key in the Browser</image:title>
      <image:caption>Every AI feature I ship sits behind a server proxy that redacts personal data before it leaves the building. Here is the shape of that proxy, and why each part exists.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/n8n-ai-automation</loc>
    <lastmod>2026-05-05</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog/n8n-ai-automation.webp</image:loc>
      <image:title>n8n: Automation That Survives the Client Handover</image:title>
      <image:caption>A workflow the client can see and edit beats a cron job only you understand.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/email-otp-2fa</loc>
    <lastmod>2026-04-28</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog/email-otp-2fa.webp</image:loc>
      <image:title>Email OTP That Is Not Security Theatre</image:title>
      <image:caption>One-time codes are easy to add and easy to get wrong. Six digits with no rate limit, no expiry, and a leaky error message is worse than no second factor at all.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/dify-llmops</loc>
    <lastmod>2026-04-28</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog/dify-llmops.webp</image:loc>
      <image:title>Dify: Giving Non-Developers a Safe AI Playground</image:title>
      <image:caption>Prompt versioning, logs, and spend limits — the boring parts that make an AI feature survive contact with a real team.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/ragas-eval</loc>
    <lastmod>2026-04-21</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog/ragas-eval.webp</image:loc>
      <image:title>Ragas: You Cannot Improve a RAG You Do Not Measure</image:title>
      <image:caption>Faithfulness, relevance, context precision. Three numbers that turn "it feels better" into a decision.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/image-heavy-cwv</loc>
    <lastmod>2026-04-16</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog/image-heavy-cwv.webp</image:loc>
      <image:title>Core Web Vitals on an Image-Heavy Site</image:title>
      <image:caption>Photography studios, interior designers, florists — my clients sell with pictures. Making those sites fast is a constraint problem, not a plugin you install.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/unsloth-finetuning</loc>
    <lastmod>2026-04-14</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog/unsloth-finetuning.webp</image:loc>
      <image:title>Unsloth: Fine-Tuning on Hardware You Already Have</image:title>
      <image:caption>Before you fine-tune anything, read the part about why your problem is probably a retrieval problem.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/openai-agents-patterns</loc>
    <lastmod>2026-04-07</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog/openai-agents-patterns.webp</image:loc>
      <image:title>Agent Patterns That Survive Production</image:title>
      <image:caption>Loop limits, tool timeouts, and a hard budget. An agent without these is an outage with a personality.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/self-host-fonts</loc>
    <lastmod>2026-04-05</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog/self-host-fonts.webp</image:loc>
      <image:title>Self-Host Your Fonts. All of Them.</image:title>
      <image:caption>Two link tags to a font CDN cost you a DNS lookup, a connection, a redirect chain, and a layout shift — on the most visible text on the page.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/owasp-llm-top-10</loc>
    <lastmod>2026-03-31</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog/owasp-llm-top-10.webp</image:loc>
      <image:title>The OWASP LLM Top 10, Translated Into Actual Fixes</image:title>
      <image:caption>Prompt injection, insecure output handling, excessive agency. Each one with the line of code that prevents it.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/client-monorepo</loc>
    <lastmod>2026-03-24</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog/client-monorepo.webp</image:loc>
      <image:title>One Monorepo Per Client</image:title>
      <image:caption>Public site, admin dashboard, API. Three apps that must agree on types and ship together. Splitting them across three repos is how small teams create integration bugs.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/prompt-injection-defense</loc>
    <lastmod>2026-03-24</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog/prompt-injection-defense.webp</image:loc>
      <image:title>Prompt Injection Is Not a Prompt Problem</image:title>
      <image:caption>You cannot instruct your way out of it. The fix is architectural: assume the model will be turned against you.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/garak-llm-scanner</loc>
    <lastmod>2026-03-17</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog/garak-llm-scanner.webp</image:loc>
      <image:title>Garak: Scan Your LLM App Before Someone Else Does</image:title>
      <image:caption>A vulnerability scanner aimed at model behaviour — jailbreaks, leakage, toxicity — run in CI like any other test.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/case-studies-not-screenshots</loc>
    <lastmod>2026-03-11</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog/case-studies-not-screenshots.webp</image:loc>
      <image:title>Write Case Studies, Not Screenshots</image:title>
      <image:caption>The five-part structure I use for every project write-up, and the one question that decides whether a paragraph stays in or gets cut.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/pyrit-red-teaming</loc>
    <lastmod>2026-03-10</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog/pyrit-red-teaming.webp</image:loc>
      <image:title>Red-Teaming Your Own AI Feature</image:title>
      <image:caption>An hour of structured attack attempts before launch is worth more than any amount of post-incident analysis.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/presidio-pii-redaction</loc>
    <lastmod>2026-03-03</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog/presidio-pii-redaction.webp</image:loc>
      <image:title>Presidio: Redaction That Beats Your Regex</image:title>
      <image:caption>My hand-rolled patterns caught emails and phones. They missed everything shaped slightly differently.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/llm-guard-output</loc>
    <lastmod>2026-02-24</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog/llm-guard-output.webp</image:loc>
      <image:title>Treat Model Output Like User Input</image:title>
      <image:caption>Rendering generated text as HTML is XSS where the payload is written by a stranger through your own feature.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/model-supply-chain</loc>
    <lastmod>2026-02-17</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog/model-supply-chain.webp</image:loc>
      <image:title>That Model File Is Executable Code</image:title>
      <image:caption>Pickle-based checkpoints can run arbitrary code on load. Downloading weights from a random mirror is not neutral.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/agentic-ai-risk</loc>
    <lastmod>2026-02-10</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog/agentic-ai-risk.webp</image:loc>
      <image:title>The Blast Radius of an Autonomous Agent</image:title>
      <image:caption>Give an agent shell access and a budget, and you have built an insider threat that never sleeps.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/nuclei-templates</loc>
    <lastmod>2026-02-03</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog/nuclei-templates.webp</image:loc>
      <image:title>Nuclei: Vulnerability Scanning You Can Read</image:title>
      <image:caption>Templates are YAML. You can audit exactly what a check does before you run it against a client.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/semgrep-custom-rules</loc>
    <lastmod>2026-01-27</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog/semgrep-custom-rules.webp</image:loc>
      <image:title>Writing a Semgrep Rule for Your Own Codebase</image:title>
      <image:caption>The generic ruleset finds generic bugs. The rule you write for your own mistake finds it forever.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/trivy-container-scanning</loc>
    <lastmod>2026-01-20</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog/trivy-container-scanning.webp</image:loc>
      <image:title>Trivy: One Scanner for Images, IaC and Dependencies</image:title>
      <image:caption>Add it to CI in ten minutes. Then spend a week deciding which findings you are actually going to fix.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/osv-scanner-deps</loc>
    <lastmod>2026-01-13</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog/osv-scanner-deps.webp</image:loc>
      <image:title>Your Dependency Tree Is Your Attack Surface</image:title>
      <image:caption>A twelve-line utility can pull in ninety packages. Every one of them runs with your privileges.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/gitleaks-secret-scanning</loc>
    <lastmod>2026-01-06</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog/gitleaks-secret-scanning.webp</image:loc>
      <image:title>The Secret You Committed Is Still in the History</image:title>
      <image:caption>Deleting the line does nothing. Rotating the credential is the only fix, and a pre-commit hook is the only prevention.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/trufflehog-verified-secrets</loc>
    <lastmod>2025-12-30</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog/trufflehog-verified-secrets.webp</image:loc>
      <image:title>Secret Scanning That Verifies Before It Alarms</image:title>
      <image:caption>A scanner that tests whether a found key is live turns a thousand false positives into three real emergencies.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/zap-dast-ci</loc>
    <lastmod>2025-12-23</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog/zap-dast-ci.webp</image:loc>
      <image:title>OWASP ZAP in CI Without Wrecking Your Pipeline</image:title>
      <image:caption>A baseline scan on every pull request, a full scan nightly. Getting that split wrong is why teams turn DAST off.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/wazuh-siem-small</loc>
    <lastmod>2025-12-16</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog/wazuh-siem-small.webp</image:loc>
      <image:title>A SIEM for Teams Who Cannot Afford a SOC</image:title>
      <image:caption>Log collection you never read is theatre. Three alerts you actually respond to is a security programme.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/sigma-detection-rules</loc>
    <lastmod>2025-12-09</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog/sigma-detection-rules.webp</image:loc>
      <image:title>Detection as Code with Sigma Rules</image:title>
      <image:caption>Write the detection once in a vendor-neutral format, convert it to whatever your SIEM speaks.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/atomic-red-team</loc>
    <lastmod>2025-12-02</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog/atomic-red-team.webp</image:loc>
      <image:title>Testing Whether Your Alerts Actually Fire</image:title>
      <image:caption>Everyone deploys detection. Almost nobody verifies it triggers. Small, safe, mapped test cases fix that.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/falco-runtime-security</loc>
    <lastmod>2025-11-25</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog/falco-runtime-security.webp</image:loc>
      <image:title>Runtime Security: Catching What the Scanner Missed</image:title>
      <image:caption>A clean image can still spawn a shell at 3am. Build-time scanning cannot see that; runtime rules can.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/projectdiscovery-recon</loc>
    <lastmod>2025-11-18</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog/projectdiscovery-recon.webp</image:loc>
      <image:title>Building a Recon Workflow With ProjectDiscovery Tools</image:title>
      <image:caption>Subfinder into httpx into nuclei. Three tools, one pipe, and the whole external surface of an authorised target.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/sigstore-signing</loc>
    <lastmod>2025-11-11</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog/sigstore-signing.webp</image:loc>
      <image:title>Signing Your Artifacts Without Managing Keys</image:title>
      <image:caption>Keyless signing tied to your CI identity. The barrier to supply-chain integrity dropped to almost nothing.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/sbom-syft-grype</loc>
    <lastmod>2025-11-04</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog/sbom-syft-grype.webp</image:loc>
      <image:title>An SBOM Is Just an Honest Inventory</image:title>
      <image:caption>When the next Log4j lands, the only question that matters is "are we affected". An SBOM answers it in seconds.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/renovate-dependency-updates</loc>
    <lastmod>2025-10-28</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog/renovate-dependency-updates.webp</image:loc>
      <image:title>Automating Dependency Updates Without Drowning</image:title>
      <image:caption>Grouping, scheduling and auto-merge for patches. Otherwise you get forty pull requests and ignore all of them.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/github-actions-hardening</loc>
    <lastmod>2025-10-21</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog/github-actions-hardening.webp</image:loc>
      <image:title>Your CI Has More Secrets Than Your Production Server</image:title>
      <image:caption>Pin actions to a commit SHA, scope permissions per job, never run untrusted code on a privileged trigger.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/infisical-secrets</loc>
    <lastmod>2025-10-14</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog/infisical-secrets.webp</image:loc>
      <image:title>Where Client Project Secrets Should Actually Live</image:title>
      <image:caption>Not in the repo, not in a WhatsApp message, not in a .env you emailed. Here is the small-team answer.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/pre-commit-hooks</loc>
    <lastmod>2025-10-07</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog/pre-commit-hooks.webp</image:loc>
      <image:title>The Pre-Commit Hooks Worth Installing Today</image:title>
      <image:caption>Secret scan, formatter, linter, large-file guard. Four hooks that prevent the four most common self-inflicted wounds.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/docker-image-slimming</loc>
    <lastmod>2025-09-30</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog/docker-image-slimming.webp</image:loc>
      <image:title>A Smaller Image Is a Smaller Attack Surface</image:title>
      <image:caption>No shell, no package manager, no curl. Most of your CVE count comes from tools your app never uses.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/biome-toolchain</loc>
    <lastmod>2025-09-23</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog/biome-toolchain.webp</image:loc>
      <image:title>Biome: Replacing Two Tools With One Fast One</image:title>
      <image:caption>Linting and formatting in a single binary. On a mid-size project the difference is seconds versus instant.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/bun-runtime</loc>
    <lastmod>2025-09-16</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog/bun-runtime.webp</image:loc>
      <image:title>Bun: Where It Wins and Where I Still Use Node</image:title>
      <image:caption>Install speed and the test runner are genuinely great. Production deployment is where I stay conservative.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/astro-islands</loc>
    <lastmod>2025-09-09</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog/astro-islands.webp</image:loc>
      <image:title>Astro: Ship Less JavaScript on Content Sites</image:title>
      <image:caption>A marketing site does not need a hydrated framework on every page. Islands make that an architecture, not a compromise.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/shadcn-copy-paste-ui</loc>
    <lastmod>2025-09-02</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog/shadcn-copy-paste-ui.webp</image:loc>
      <image:title>The Copy-Paste Component Model</image:title>
      <image:caption>You own the file, so you can restyle it into a brutalist theme without fighting a library you cannot edit.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/playwright-e2e</loc>
    <lastmod>2025-08-26</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog/playwright-e2e.webp</image:loc>
      <image:title>Playwright: The Only Tests Clients Ever Notice</image:title>
      <image:caption>Unit tests protect you. End-to-end tests protect the checkout. Guess which one the client cares about.</image:caption>
    </image:image>
  </url>

  <url>
    <loc>https://omarbadran.dev/blog/zod-runtime-validation</loc>
    <lastmod>2025-08-19</lastmod>
    <changefreq>yearly</changefreq>
    <priority>0.6</priority>
    <image:image>
      <image:loc>https://omarbadran.dev/img/blog/zod-runtime-validation.webp</image:loc>
      <image:title>TypeScript Types Vanish at Runtime</image:title>
      <image:caption>Your compile-time safety does nothing to a malformed request body. One schema per route closes the gap.</image:caption>
    </image:image>
  </url>
</urlset>
