<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Aniq Haider</title>
    <description>The latest articles on DEV Community by Aniq Haider (@haideraniq).</description>
    <link>https://dev.to/haideraniq</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4200183%2F9ffb9651-5e26-4d3b-ae7a-2195e6ce17c7.jpg</url>
      <title>DEV Community: Aniq Haider</title>
      <link>https://dev.to/haideraniq</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/haideraniq"/>
    <language>en</language>
    <item>
      <title>An editor update system with a human approval gate on every write</title>
      <dc:creator>Aniq Haider</dc:creator>
      <pubDate>Thu, 22 Oct 2026 10:17:38 +0000</pubDate>
      <link>https://dev.to/haideraniq/an-editor-update-system-with-a-human-approval-gate-on-every-write-230c</link>
      <guid>https://dev.to/haideraniq/an-editor-update-system-with-a-human-approval-gate-on-every-write-230c</guid>
      <description>&lt;p&gt;A visual editor stores each page as structured template data behind an API. Changing that data in bulk is powerful, and also easy to get catastrophically wrong. I built an editor update system around one rule: reads are free, writes are never automatic.&lt;/p&gt;

&lt;h3&gt;
  
  
  Safe change workflow
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;Every mutating call passes through the same gate. Nothing is batched under one approval.&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;UNDERSTAND
      API catalog  (Every endpoint recorded with a verified response shape)
  ──▶ GET and inspect  (Reads run freely to see the real data)
  ──▶ Plan the change  (Exact request body, reviewed before it is sent)

CHANGE
      Approval gate  (A person confirms each POST, PUT, PATCH or DELETE)
  ──▶ Backup first  (For deletes, save the full template JSON to disk)
  ──▶ Mutate  (One call at a time)
  ──▶ Verify with GET  (Confirm the saved shape matches the plan)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The design decisions
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;An isolated workspace with its own instructions, so nothing bleeds into other projects and the rules are impossible to miss.&lt;/li&gt;
&lt;li&gt;A growing, append-only API catalog. Each endpoint is recorded with its method, whether it mutates, a working request and the response shape I actually observed.&lt;/li&gt;
&lt;li&gt;Backup before delete is mandatory. A deleted template is saved with a timestamp, and restoring it is a single PUT of the saved page configuration.&lt;/li&gt;
&lt;li&gt;Approvals do not carry over: a similar call approved earlier in the session does not authorise the next one.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;The goal is speed without fear. Automation does the tedious inspection and bookkeeping, and a person keeps the final say on anything that changes live data.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://aniq-haider.vercel.app/blog/editor-update-system" rel="noopener noreferrer"&gt;my portfolio&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>api</category>
      <category>automation</category>
      <category>webdev</category>
      <category>ai</category>
    </item>
    <item>
      <title>github-repo-mcp: letting an AI explore any GitHub repo without cloning it by hand</title>
      <dc:creator>Aniq Haider</dc:creator>
      <pubDate>Thu, 22 Oct 2026 10:17:17 +0000</pubDate>
      <link>https://dev.to/haideraniq/github-repo-mcp-letting-an-ai-explore-any-github-repo-without-cloning-it-by-hand-n2d</link>
      <guid>https://dev.to/haideraniq/github-repo-mcp-letting-an-ai-explore-any-github-repo-without-cloning-it-by-hand-n2d</guid>
      <description>&lt;p&gt;When an assistant needs to understand a codebase it does not have locally, the usual options are pasting files or cloning by hand. I wanted something better: point the assistant at owner/repo and let it explore, the way a developer would. So I wrote github-repo-mcp, a local Model Context Protocol server.&lt;/p&gt;

&lt;h3&gt;
  
  
  Architecture
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;The server runs over stdio. Repos are cloned once and reused from a local cache.&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;REQUEST PATH
      Claude  (MCP client)
  ──▶ github-repo-mcp  (stdio server, written in TypeScript on Bun)
  ──▶ Local clone cache  (~/.cache/github-repo-mcp/owner/repo)
  ──▶ GitHub  (Cloned once, pulled on refresh)

FIVE TOOLS
      load_repo  (Clone or reuse, return a summary)
  ──▶ get_repo_map  (Files and exported symbols)
  ──▶ grep  (Regex search with context)
  ──▶ read_file  (A file or a line range)
  ──▶ refresh_repo  (Pull latest, invalidate the map)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How it works
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;load_repo clones a repo (or reuses the cached copy) and returns languages, file count, a top-level tree and a README excerpt, enough to decide where to look next.&lt;/li&gt;
&lt;li&gt;get_repo_map builds a structural map of paths and exported symbols. TypeScript gets a fast extraction path, and other languages such as Python are parsed with tree-sitter.&lt;/li&gt;
&lt;li&gt;grep uses ripgrep for speed and falls back to a pure-JS search when ripgrep is not installed.&lt;/li&gt;
&lt;li&gt;A GitHub token is optional and only needed for private repos. Path guards keep reads inside the cloned repo.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The workflow it enables
&lt;/h2&gt;

&lt;p&gt;Load the repo, read the map to find the right module, grep for the call sites, then read only the lines that matter. The assistant spends its context on understanding the code and not on scrolling through it.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It is a small server with a deliberately small surface: five tools, one cache directory, and tests around the guards and the parser.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://aniq-haider.vercel.app/blog/github-repo-mcp" rel="noopener noreferrer"&gt;my portfolio&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>mcp</category>
      <category>typescript</category>
      <category>ai</category>
      <category>productivity</category>
    </item>
    <item>
      <title>A multi-agent pipeline that clones live sites into production components</title>
      <dc:creator>Aniq Haider</dc:creator>
      <pubDate>Thu, 22 Oct 2026 10:16:55 +0000</pubDate>
      <link>https://dev.to/haideraniq/a-multi-agent-pipeline-that-clones-live-sites-into-production-components-343i</link>
      <guid>https://dev.to/haideraniq/a-multi-agent-pipeline-that-clones-live-sites-into-production-components-343i</guid>
      <description>&lt;p&gt;Rebuilding a page section by hand means inspecting the DOM, copying design tokens, chasing hover states and fixing responsive breakpoints. It is slow, and it is mostly mechanical. I built a pipeline of Claude Code subagents that does the mechanical part and leaves the review to a human.&lt;/p&gt;

&lt;h3&gt;
  
  
  How a clone run flows
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;Sections run strictly one at a time, so each agent keeps a small, clean context.&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ONCE PER PAGE
      Input  (Live URL or Figma frames)
  ──▶ Phase 0 · Discover  (Scroll, find sections, capture 4 breakpoints)
  ──▶ Pick sections  (One, several, or all)

FOR EACH SECTION, IN ORDER
      Phase 1 · Harvest  (Tokens, assets, hover and scroll behaviour, screenshots)
  ──▶ Compress  (Shrink the handoff JSON before the next agent reads it)
  ──▶ Phase 2 · Build UI  (Widget code wired into the page template)
  ──▶ Verify build  (Pass moves on. Fail retries, up to 3 times)

AFTER THE RUN
      Hill-climb  (Mine notes and failures into reusable rules)
  ──▶ learnings.md  (Read by every agent at the start of the next run)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Why separate agents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Each phase has one job and one output file (sections.json, harvest.json, the generated widget). A failed phase can be re-run without redoing the others.&lt;/li&gt;
&lt;li&gt;The main session orchestrates instead of a nested orchestrator agent. That saves context, and I can step in between phases.&lt;/li&gt;
&lt;li&gt;A Figma branch replaces only the discovery and harvest agents. It emits the same files, so the UI agent is reused untouched.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What keeps it reliable
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A hard build gate: a section only counts as done when the project builds. Errors go back to the agent for up to three retries.&lt;/li&gt;
&lt;li&gt;Guardrails written into the pipeline: shared directories are off limits, and protected files may only be changed by commenting out the original, never deleting it.&lt;/li&gt;
&lt;li&gt;A learning loop. Every run's notes and failures are distilled into rules the next run reads, so the same mistake is not repeated.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;The result: new sections that used to take days now take hours, and most of that time is human review instead of pixel-pushing.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Source code:&lt;/strong&gt; a generic version of the agents is on GitHub: &lt;a href="https://github.com/AniqHaider/site-clone-agents" rel="noopener noreferrer"&gt;AniqHaider/site-clone-agents&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://aniq-haider.vercel.app/blog/agent-cloning-pipeline" rel="noopener noreferrer"&gt;my portfolio&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>nextjs</category>
      <category>automation</category>
    </item>
    <item>
      <title>Cardify: restyling a storefront's product cards without touching its code</title>
      <dc:creator>Aniq Haider</dc:creator>
      <pubDate>Thu, 22 Oct 2026 10:05:10 +0000</pubDate>
      <link>https://dev.to/haideraniq/cardify-restyling-a-storefronts-product-cards-without-touching-its-code-om5</link>
      <guid>https://dev.to/haideraniq/cardify-restyling-a-storefronts-product-cards-without-touching-its-code-om5</guid>
      <description>&lt;p&gt;Every merchant eventually asks the same thing: "Can our product cards look different?"&lt;/p&gt;

&lt;p&gt;On a commerce platform, that request is more expensive than it sounds. A product card is not one component. It shows up in collection grids, carousels, search results and related-product rows, and each of those widgets renders its own markup. Changing the look of a card means touching all of them, for every storefront that wants it.&lt;/p&gt;

&lt;p&gt;I built &lt;strong&gt;Cardify&lt;/strong&gt; to avoid that. It is an app that restyles product cards from the outside. The merchant opens an admin screen, flips a switch, picks one of five designs, and the storefront's own cards are replaced live. No storefront redeploy, no page reload, no edits to the widgets that render the cards.&lt;/p&gt;

&lt;p&gt;It is now running in production on 16 storefronts on the Ratio platform.&lt;/p&gt;

&lt;h2&gt;
  
  
  How a card gets replaced
&lt;/h2&gt;

&lt;p&gt;The storefront exposes only a few data attributes on its native cards. Everything else is loaded on demand. There are three flows to understand: setup, what happens on the storefront, and what happens when a shopper clicks.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SETUP (merchant)
  Merchant admin ──▶ Settings API ──▶ Public config
  React + Vite       Fastify + MySQL   Read-only endpoint
  switch on, pick    admin writes are  the storefront
  design + colours   key-protected     loader calls

ON THE STOREFRONT (every page load)
  Tiny loader ──▶ Config says off? ──yes──▶ do nothing, native cards stay
  0.5 KB gzip          │
  fetches config       no
                       ▼
                  Load widget ──▶ Overlay
                  ~10 KB gzip,    hide each native card,
                  imported lazily mount a Cardify card in its cell

WHEN A SHOPPER CLICKS
  Cardify card ──▶ Hidden native link ──▶ Store behaviour runs
  click or         click is delegated     routing, quick-buy popup
  quick-buy        to the store's own     and analytics, unchanged
                   element
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important part is the second flow. The loader is tiny, about half a kilobyte gzipped, and its only job is to fetch the merchant's config. If Cardify is switched off, it does nothing and the shopper never downloads anything else. If it is on, the widget, about 10 KB gzipped, is imported lazily, hides each native card and mounts a Cardify card in the same cell.&lt;/p&gt;

&lt;h2&gt;
  
  
  Design choices that matter
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Purely cosmetic.&lt;/strong&gt; A Cardify card uses exactly the data the native card already renders. There is no new data contract for the storefront to maintain, which is a big part of why it can be dropped onto a store without a conversation with that store's developers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Native cards are hidden, never removed.&lt;/strong&gt; The overlay mounts inside the same cell, so the store's grid and carousel layout stays untouched. A &lt;code&gt;MutationObserver&lt;/code&gt; picks up cards that appear later, such as items loaded by infinite scroll or a filter change.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Behaviour is delegated back to the host.&lt;/strong&gt; When a shopper clicks a Cardify card, it clicks the hidden native link. The store's own routing, quick-buy popup and tracking keep running exactly as before. Cardify never has to reimplement any of it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It fails safe.&lt;/strong&gt; If the backend is down, the config call errors or the bundle is blocked, the shopper simply sees the original cards. The worst case is "Cardify did nothing", never a broken product grid.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No polling.&lt;/strong&gt; The config refreshes on page load and when the tab regains focus. A timer would make every visitor's open tab hit the backend, for no benefit.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The server refuses to start without an admin key.&lt;/strong&gt; A missing environment variable can never silently mean an open admin.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Five designs, one structure
&lt;/h2&gt;

&lt;p&gt;The five designs are classic, minimal, overlay, hover-reveal and editorial. They all share one DOM structure and differ only in CSS. That is the reason click and quick-buy bridging works for every design for free: the elements the bridge looks for are in the same place in all of them.&lt;/p&gt;

&lt;p&gt;Merchants can tune accent, text and background colours, corner radius and image shape, and toggle the badge, quick-buy, rating and compare-at price. Every setting is validated with a shared &lt;a href="https://zod.dev" rel="noopener noreferrer"&gt;zod&lt;/a&gt; schema, used by both the admin and the API, so the two cannot drift apart.&lt;/p&gt;

&lt;p&gt;Adding a sixth design is a registry entry plus one CSS block.&lt;/p&gt;

&lt;h2&gt;
  
  
  Status
&lt;/h2&gt;

&lt;p&gt;Cardify is live in production on 16 storefronts. It is covered by unit tests and a headless-Chromium end-to-end suite that runs the real overlay against mocked storefront pages.&lt;/p&gt;

&lt;p&gt;The stack: Lit for the storefront widget, Fastify and MySQL for the API, React and Vite for the admin, and Playwright for the end-to-end tests.&lt;/p&gt;

&lt;p&gt;If you are building something that has to live inside someone else's page, the lesson I would pass on is this: hide, don't remove, delegate instead of reimplementing, and make every failure path end in "the original page, unchanged".&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Source code:&lt;/strong&gt; a lightweight, self-contained version is on GitHub: &lt;a href="https://github.com/AniqHaider/cardify-lite" rel="noopener noreferrer"&gt;AniqHaider/cardify-lite&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://aniq-haider.vercel.app/blog/cardify" rel="noopener noreferrer"&gt;my portfolio&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>ecommerce</category>
      <category>frontend</category>
    </item>
  </channel>
</rss>
