<?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: Orchid Files</title>
    <description>The latest articles on DEV Community by Orchid Files (@orchidfiles).</description>
    <link>https://dev.to/orchidfiles</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%2F3625701%2F579307cf-8816-4794-bbdf-95beb86470bf.png</url>
      <title>DEV Community: Orchid Files</title>
      <link>https://dev.to/orchidfiles</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/orchidfiles"/>
    <language>en</language>
    <item>
      <title>Why localhost doesn't work as OpenAI Base URL in Cursor — and how to fix it</title>
      <dc:creator>Orchid Files</dc:creator>
      <pubDate>Tue, 11 Aug 2026 09:20:44 +0000</pubDate>
      <link>https://dev.to/orchidfiles/why-localhost-doesnt-work-as-openai-base-url-in-cursor-and-how-to-fix-it-589e</link>
      <guid>https://dev.to/orchidfiles/why-localhost-doesnt-work-as-openai-base-url-in-cursor-and-how-to-fix-it-589e</guid>
      <description>&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; Cursor doesn't call your OpenAI Base URL from your local machine. It routes every request through its backend servers on &lt;code&gt;api2.cursor.sh&lt;/code&gt;, so &lt;code&gt;http://localhost:8082&lt;/code&gt; is unreachable — the chat hangs and your proxy logs stay empty. To connect Ollama, LM Studio, LiteLLM, or a custom subscription proxy, you must expose your local port through a public URL — a Cloudflare tunnel is the simplest way, and it is what the Ungate extension automates.&lt;/p&gt;




&lt;p&gt;When I first wrote a local Fastify proxy to connect my Claude subscription to Cursor, the setup felt trivial: start the server on port 8082, open &lt;code&gt;Cursor Settings → Models → Override OpenAI Base URL&lt;/code&gt;, paste &lt;code&gt;http://localhost:8082/v1&lt;/code&gt;, and hit save. I typed a prompt into chat, hit Enter, and watched the status indicator spin forever.&lt;/p&gt;

&lt;p&gt;I opened terminal logs expecting to see incoming HTTP requests. Nothing. I ran &lt;code&gt;tcpdump&lt;/code&gt; on my loopback interface — zero packets from Cursor.&lt;/p&gt;

&lt;p&gt;I spent an hour double-checking port bindings and firewall rules before realizing the issue wasn't in my code. It is in how Cursor is built.&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;h2&gt;
  
  
  How Cursor actually routes OpenAI Base URL requests
&lt;/h2&gt;

&lt;p&gt;Unlike VS Code extensions, Aider, or Continue.dev — which send LLM API calls directly from your local Node process — Cursor processes chat and agent context on its own remote servers (&lt;code&gt;api2.cursor.sh&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;When you select a model and send a message, the request path is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Cursor UI
   ↓
Cursor's cloud backend
   ↓
Override OpenAI Base URL
   ↓
LLM Provider
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because the third step originates from Cursor's cloud backend over the public internet, &lt;code&gt;http://localhost:8082/v1&lt;/code&gt; resolves to the backend server's own loopback interface — not your laptop.&lt;/p&gt;

&lt;p&gt;This breaks every local setup out of the box. Whether you are trying to route Cursor through Ollama (&lt;code&gt;http://localhost:11434&lt;/code&gt;), LiteLLM (&lt;code&gt;http://localhost:4000&lt;/code&gt;), vLLM, or a custom proxy, Cursor's backend simply cannot reach your machine's &lt;code&gt;localhost&lt;/code&gt;. The safe version of the same idea, &lt;code&gt;cursor localhost base url not working&lt;/code&gt;, is exactly the symptom this post explains.&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why it looks like a broken proxy
&lt;/h2&gt;

&lt;p&gt;When &lt;code&gt;http://localhost:8082/v1&lt;/code&gt; is configured in Cursor Settings:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The Cursor UI sends your prompt and context to &lt;code&gt;api2.cursor.sh&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The Cursor backend tries to POST to &lt;code&gt;http://localhost:8082/v1/chat/completions&lt;/code&gt; from its cloud servers.&lt;/li&gt;
&lt;li&gt;The connection is refused or times out on the remote server.&lt;/li&gt;
&lt;li&gt;Cursor UI shows "Reconnecting..." or a generic request error (500, 404, or a timeout).&lt;/li&gt;
&lt;li&gt;Your local proxy logs stay 100% empty because no TCP connection ever touched your machine.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This makes debugging infuriating. The empty logs suggest your proxy isn't listening, when in reality the request died thousands of miles away before reaching your network.&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;h2&gt;
  
  
  Prove it to yourself in 2 minutes
&lt;/h2&gt;

&lt;p&gt;You can confirm this exact behavior right now without changing your proxy code.&lt;/p&gt;

&lt;p&gt;First, check that your local server works:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl http://localhost:8082/health
&lt;span class="c"&gt;# → 200 OK&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Second, start an ad-hoc Cloudflare tunnel to expose that port publicly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cloudflared tunnel &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--config&lt;/span&gt; /dev/null &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--url&lt;/span&gt; http://localhost:8082
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Grab the generated &lt;code&gt;https://&amp;lt;random&amp;gt;.trycloudflare.com&lt;/code&gt; URL from terminal output and test it from outside your local network (for example, from your phone over LTE):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl https://&amp;lt;random&amp;gt;.trycloudflare.com/health
&lt;span class="c"&gt;# → 200 OK&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Paste that &lt;code&gt;https://...&lt;/code&gt; address into &lt;code&gt;Cursor Settings → Models → Override OpenAI Base URL&lt;/code&gt;. Send a prompt in Cursor chat. Your local proxy logs will instantly light up with incoming requests.&lt;/p&gt;

&lt;p&gt;Switch the setting back to &lt;code&gt;http://localhost:8082/v1&lt;/code&gt;, and it immediately hangs again. Same machine, same code, different origin.&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why a public tunnel is required by design
&lt;/h2&gt;

&lt;p&gt;To let Cursor's cloud backend talk to a local process on your laptop, you need a public endpoint that routes back to your machine.&lt;/p&gt;

&lt;p&gt;A Cloudflare tunnel creates an outbound-only WebSocket connection from your machine to Cloudflare's edge network:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Cursor backend
   ↓
https://&amp;lt;tunnel&amp;gt;.trycloudflare.com
   ↓
Cloudflare Edge
   ↓
Local machine (port 8082)
   ↑
outbound-only connection
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because your machine initiates the connection outward, you don't need port forwarding, static IPs, or open inbound firewall ports.&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;h2&gt;
  
  
  Tunnel configuration pitfalls that look like localhost bugs
&lt;/h2&gt;

&lt;p&gt;Once people switch to a tunnel URL, they sometimes hit a new set of errors that look identical to the localhost issue:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cloudflare returns 404 instead of reaching your proxy:&lt;/strong&gt; If you have &lt;code&gt;cloudflared&lt;/code&gt; installed locally, it may silently read &lt;code&gt;~/.cloudflared/config.yml&lt;/code&gt;. If that config contains ingress rules with a catch-all &lt;code&gt;http_status:404&lt;/code&gt; from a previous named tunnel, your quick tunnel will return Cloudflare's 404 page. Prevent this by passing &lt;code&gt;--config /dev/null&lt;/code&gt; (see the command below).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;HTTP 429 Too Many Requests:&lt;/strong&gt; Anonymous &lt;code&gt;trycloudflare.com&lt;/code&gt; quick tunnels share rate limits per IP. For permanent setups, use a named tunnel tied to a free Cloudflare account.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Port mismatch:&lt;/strong&gt; Your proxy is listening on &lt;code&gt;8082&lt;/code&gt;, but &lt;code&gt;cloudflared&lt;/code&gt; was started pointing at &lt;code&gt;8080&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;404 from Cloudflare vs 404 from proxy:&lt;/strong&gt; If &lt;code&gt;curl https://&amp;lt;tunnel&amp;gt;/health&lt;/code&gt; returns &lt;code&gt;404&lt;/code&gt; with a &lt;code&gt;server: cloudflare&lt;/code&gt; header, the tunnel isn't reaching your port. If it returns a JSON error, the request reached your proxy.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To force a quick tunnel to ignore &lt;code&gt;~/.cloudflared/config.yml&lt;/code&gt; entirely:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cloudflared tunnel &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--config&lt;/span&gt; /dev/null &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--url&lt;/span&gt; http://localhost:8082 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--edge-ip-version&lt;/span&gt; 4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step-by-step debugging checklist
&lt;/h2&gt;

&lt;p&gt;If requests in Cursor chat hang or fail when using a custom Base URL:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Verify protocol:&lt;/strong&gt; Is your &lt;code&gt;Override OpenAI Base URL&lt;/code&gt; set to &lt;code&gt;https://&lt;/code&gt;? Plain &lt;code&gt;http://localhost&lt;/code&gt; will never work.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test external connectivity:&lt;/strong&gt; Run &lt;code&gt;curl https://&amp;lt;your-tunnel-url&amp;gt;/health&lt;/code&gt; from a non-local network (e.g., mobile hot spot).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Check Cloudflare response headers:&lt;/strong&gt; If curl returns a 404, check the headers. If &lt;code&gt;server: cloudflare&lt;/code&gt; is present, fix the tunnel flags (&lt;code&gt;--config /dev/null&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inspect proxy authentication:&lt;/strong&gt; Only after confirming the tunnel reaches your machine should you inspect OAuth tokens, API keys, or provider formats.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;There is one more unrelated Cursor quirk: it silently unchecks the &lt;code&gt;Override OpenAI Base URL&lt;/code&gt; setting every few hours, which silently sends requests through your API tokens instead. If your proxy suddenly stops receiving requests, check that checkbox first — I explain this bug in my &lt;a href="https://dev.to/orchidfiles/how-to-use-a-claude-subscription-in-cursor-without-paying-for-api-tokens-1bfa"&gt;post about using Claude and ChatGPT subscriptions in Cursor&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;h2&gt;
  
  
  How Ungate automates this in Cursor
&lt;/h2&gt;

&lt;p&gt;Setting up &lt;code&gt;cloudflared&lt;/code&gt; manually every time you launch Cursor gets tedious. That's why I built Ungate — an open-source Cursor extension that connects Claude and ChatGPT subscriptions directly to native Cursor chat.&lt;/p&gt;

&lt;p&gt;Ungate handles the entire proxy lifecycle automatically:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Starts a local proxy on an isolated port.&lt;/li&gt;
&lt;li&gt;Spawns a platform-specific &lt;code&gt;cloudflared&lt;/code&gt; binary with &lt;code&gt;--config /dev/null&lt;/code&gt; to bypass local config conflicts.&lt;/li&gt;
&lt;li&gt;Generates a local proxy API key so public tunnel URLs cannot be abused by unauthorized third parties.&lt;/li&gt;
&lt;li&gt;Displays live proxy logs, request analytics, and tunnel status right inside Cursor's UI.&lt;/li&gt;
&lt;li&gt;Auto-re-enables the Base URL setting when Cursor silently disables it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can install Ungate by searching for &lt;code&gt;@id:orchidfiles.ungate&lt;/code&gt; in Cursor Extensions, or read the full setup guide here: &lt;a href="https://dev.to/orchidfiles/how-to-use-a-claude-subscription-in-cursor-without-paying-for-api-tokens-1bfa"&gt;How to use Claude and ChatGPT subscriptions in Cursor&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;GitHub repository: &lt;a href="https://github.com/orchidfiles/ungate" rel="noopener noreferrer"&gt;https://github.com/orchidfiles/ungate&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;My Blog: &lt;a href="https://orchidfiles.com/" rel="noopener noreferrer"&gt;orchidfiles.com&lt;/a&gt;&lt;br&gt;
Telegram Channel: &lt;a href="https://t.me/orchidfiles" rel="noopener noreferrer"&gt;@orchidfiles&lt;/a&gt;&lt;/p&gt;

</description>
      <category>cursor</category>
      <category>openai</category>
      <category>devops</category>
      <category>claude</category>
    </item>
    <item>
      <title>I built LoreData: a mock data generator with characters from Breaking Bad, Game of Thrones, Harry Potter, and other universes.</title>
      <dc:creator>Orchid Files</dc:creator>
      <pubDate>Mon, 13 Apr 2026 16:47:01 +0000</pubDate>
      <link>https://dev.to/orchidfiles/i-built-loredata-a-mock-data-generator-with-characters-from-breaking-bad-game-of-thrones-harry-70j</link>
      <guid>https://dev.to/orchidfiles/i-built-loredata-a-mock-data-generator-with-characters-from-breaking-bad-game-of-thrones-harry-70j</guid>
      <description>&lt;p&gt;In product demos, you often see names like John Doe, Jane Smith, Test User, and random emails like &lt;code&gt;test@example.com&lt;/code&gt;. That works fine for smoke tests. It falls short in demos, seeds, mockups, and showcase pages.&lt;/p&gt;

&lt;p&gt;The problem is not that the data is fake. The problem is that it is incoherent: the name and address are random, the &lt;code&gt;bio&lt;/code&gt; feels disconnected, and the persona's interests and profession feel generated. In a demo, that is obvious right away.&lt;/p&gt;

&lt;p&gt;I wanted a generator that builds not just a random set of fields, but a coherent persona from a single fictional universe.&lt;/p&gt;

&lt;p&gt;Demo: &lt;a href="https://loredata.orchidfiles.com" rel="noopener noreferrer"&gt;https://loredata.orchidfiles.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;h3&gt;
  
  
  What LoreData does
&lt;/h3&gt;

&lt;p&gt;LoreData generates personas from pop culture universes: The Simpsons, Star Wars, The Sopranos, and more. It currently supports 25 universes. Every field in a persona comes from the same universe.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;person&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;group&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;loredata&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;person&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;universe&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;breaking-bad&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="c1"&gt;// {&lt;/span&gt;
&lt;span class="c1"&gt;//   firstName: 'Walter',&lt;/span&gt;
&lt;span class="c1"&gt;//   lastName: 'White',&lt;/span&gt;
&lt;span class="c1"&gt;//   username: 'heisenberg',&lt;/span&gt;
&lt;span class="c1"&gt;//   email: 'blue_sky_cook@lospollos.com',&lt;/span&gt;
&lt;span class="c1"&gt;//   quote: "I am the one who knocks.",&lt;/span&gt;
&lt;span class="c1"&gt;//   profession: 'Chemistry teacher',&lt;/span&gt;
&lt;span class="c1"&gt;//   interests: ['chemistry', 'cooking', 'family'],&lt;/span&gt;
&lt;span class="c1"&gt;//   address: { street: '308 Negra Arroyo Lane', city: 'Albuquerque', state: 'NM' },&lt;/span&gt;
&lt;span class="c1"&gt;//   symbol: '☢️',&lt;/span&gt;
&lt;span class="c1"&gt;//   universe: 'breaking-bad'&lt;/span&gt;
&lt;span class="c1"&gt;// }&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can generate a group too:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;team&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;group&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;universe&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;game-of-thrones&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="c1"&gt;// [&lt;/span&gt;
&lt;span class="c1"&gt;//   { firstName: 'Jon', lastName: 'Snow', username: 'lord_commander', ... },&lt;/span&gt;
&lt;span class="c1"&gt;//   { firstName: 'Daenerys', lastName: 'Targaryen', username: 'mother_of_dragons', ... },&lt;/span&gt;
&lt;span class="c1"&gt;//   { firstName: 'Tyrion', lastName: 'Lannister', username: 'halfman', ... },&lt;/span&gt;
&lt;span class="c1"&gt;// ]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;h3&gt;
  
  
  This is not a replacement for Faker.js
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;Faker.js&lt;/code&gt; generates realistic random data. The fields may be valid, but within a single persona they are not really connected: there is no shared context and no character identity. LoreData solves a different problem: personas for interfaces, where recognizability and internal consistency matter more than field validity alone.&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;h3&gt;
  
  
  Install and CLI
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;loredata        &lt;span class="c"&gt;# library&lt;/span&gt;
npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; loredata     &lt;span class="c"&gt;# CLI&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The CLI supports filtering by interests, name, and output format:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;loredata person &lt;span class="nt"&gt;--universe&lt;/span&gt; sherlock
loredata person &lt;span class="nt"&gt;--interests&lt;/span&gt; chemistry,cooking
loredata person &lt;span class="nt"&gt;--interests&lt;/span&gt; chemistry,cooking &lt;span class="nt"&gt;--interests-mode&lt;/span&gt; and
loredata person &lt;span class="nt"&gt;--name&lt;/span&gt; walter &lt;span class="nt"&gt;--format&lt;/span&gt; json
loredata group &lt;span class="nt"&gt;--universe&lt;/span&gt; friends &lt;span class="nt"&gt;--size&lt;/span&gt; 5
loredata universes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;h3&gt;
  
  
  Deterministic output
&lt;/h3&gt;

&lt;p&gt;If you need reproducible results, for example for test fixtures, just pass a &lt;code&gt;seed&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;person&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;universe&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;matrix&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;seed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;team&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;group&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;universe&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;matrix&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;seed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Given the same &lt;code&gt;seed&lt;/code&gt;, you always get the same persona or the same group of personas.&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;h3&gt;
  
  
  Browser entry point
&lt;/h3&gt;

&lt;p&gt;The library also supports browser environments through a separate entry point with no dependency on &lt;code&gt;fs&lt;/code&gt; or &lt;code&gt;path&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;loadUniverse&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;personFromData&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;loredata/browser&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;universe&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;loadUniverse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;breaking-bad&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;personFromData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;universe&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It works with Vite, webpack, and any browser bundler.&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;h3&gt;
  
  
  How the project is structured
&lt;/h3&gt;

&lt;p&gt;It is a TypeScript monorepo built with &lt;code&gt;pnpm&lt;/code&gt;. It includes an npm package with the library, a CLI, and a web app for the demo.&lt;/p&gt;

&lt;p&gt;The data lives in JSON datasets: each universe has separate files for metadata, characters, and addresses. To add a new universe, you only need to create &lt;code&gt;data/{id}/meta.json&lt;/code&gt;, &lt;code&gt;data/{id}/characters.json&lt;/code&gt;, and &lt;code&gt;data/{id}/addresses.json&lt;/code&gt;. There is no manual registry. The loader picks up the new folder automatically.&lt;/p&gt;

&lt;p&gt;Here, the data matters as much as the code. Product quality depends on canon accuracy: the right professions, real locations from the source material, and quotes that fit the character. AI agents handle about 90% of the dataset drafting work.&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;h3&gt;
  
  
  Who this is for
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;developers filling a local database or Storybook stories with recognizable personas&lt;/li&gt;
&lt;li&gt;designers building mockups who do not want to use John Doe again&lt;/li&gt;
&lt;li&gt;QA engineers creating more expressive test accounts with different profiles&lt;/li&gt;
&lt;li&gt;tutorial and conference talk authors who want screenshots that feel less generic&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;h3&gt;
  
  
  Disclaimer
&lt;/h3&gt;

&lt;p&gt;LoreData is an unofficial fan tool and is not affiliated with the rights holders of these universes, studios, or streaming platforms.&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;h3&gt;
  
  
  Links
&lt;/h3&gt;

&lt;p&gt;The project is open source. PRs with new universes are welcome.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;demo: &lt;a href="https://loredata.orchidfiles.com" rel="noopener noreferrer"&gt;loredata.orchidfiles.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;repository: &lt;a href="https://github.com/orchidfiles/loredata" rel="noopener noreferrer"&gt;github.com/orchidfiles/loredata&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;npm: &lt;a href="https://www.npmjs.com/package/loredata" rel="noopener noreferrer"&gt;npmjs.com/package/loredata&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;If this post was interesting to you, you might also enjoy my writing on my blog: &lt;a href="https://orchidfiles.com/" rel="noopener noreferrer"&gt;orchidfiles.com&lt;/a&gt;&lt;br&gt;
I also publish shorter pieces on my Telegram channel: &lt;a href="https://t.me/orchidfiles" rel="noopener noreferrer"&gt;@orchidfiles&lt;/a&gt;&lt;br&gt;
Either way, thanks for reading.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>typescript</category>
      <category>node</category>
      <category>webdev</category>
    </item>
    <item>
      <title>How to Connect MiniMax-M3 to Cursor</title>
      <dc:creator>Orchid Files</dc:creator>
      <pubDate>Fri, 03 Apr 2026 10:30:38 +0000</pubDate>
      <link>https://dev.to/orchidfiles/how-to-connect-minimax-m27-to-cursor-3kn0</link>
      <guid>https://dev.to/orchidfiles/how-to-connect-minimax-m27-to-cursor-3kn0</guid>
      <description>&lt;h2&gt;
  
  
  The Missing Thinking and Reasoning Separation in Cursor
&lt;/h2&gt;

&lt;p&gt;The documentation on the MiniMax website states that the model uses the OpenAI format and is compatible with most IDEs. But it turned out that if you connect it to Cursor, it doesn't separate the contents of &lt;code&gt;&amp;lt;think&amp;gt;...&amp;lt;/think&amp;gt;&lt;/code&gt; from the actual response; everything goes into a single stream. You see the model's thoughts and the response mixed together, and at some point it becomes unclear where its thoughts end and the response to the user begins. Working in this mode is extremely inconvenient.&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;h2&gt;
  
  
  How Ungate Fixes It
&lt;/h2&gt;

&lt;p&gt;I've added MiniMax support to the &lt;a href="https://github.com/orchidfiles/ungate" rel="noopener noreferrer"&gt;Ungate extension for Cursor&lt;/a&gt; that I'm developing. It processes content from &lt;code&gt;&amp;lt;think&amp;gt;...&amp;lt;/think&amp;gt;&lt;/code&gt; blocks, and now Cursor correctly separates the model's reasoning from the response to the user. Working with MiniMax in Cursor is now the same as with other OpenAI-compatible models.&lt;/p&gt;

&lt;p&gt;Without Ungate, the model's thoughts and the answer arrive in one stream — a single text block where the reasoning and the response run together:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;think&amp;gt;... I need to check the project structure first. Let me list the files
and then propose a plan...&amp;lt;/think&amp;gt; But the actual answer continues right here,
so it is unclear where the thinking ends and the response begins.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With Ungate, Cursor correctly separates the model's reasoning from the response, and only the answer reaches the chat:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Here is the final plan for the task.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Login and tunnel setup for the extension are the same for MiniMax as for other models — see &lt;a href="https://dev.to/orchidfiles/how-to-use-a-claude-subscription-in-cursor-without-paying-for-api-tokens-1bfa"&gt;How to use Claude and ChatGPT subscriptions in Cursor&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;h2&gt;
  
  
  Connecting MiniMax in Cursor
&lt;/h2&gt;

&lt;p&gt;To access the model, you need to add the custom model name to Cursor:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MiniMax-M3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I've added a Base URL selector for MiniMax to the Ungate settings:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;China&lt;/li&gt;
&lt;li&gt;Global&lt;/li&gt;
&lt;li&gt;Custom&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;h2&gt;
  
  
  Quality and Speed: Benchmarks vs Practice
&lt;/h2&gt;

&lt;p&gt;MiniMax-M3 is a new Chinese frontier model from MiniMax. According to some benchmarks, it has almost caught up with Claude Opus 5. However, based on my tests over the past few days, I've concluded that it doesn't even measure up to Claude Sonnet 5. If you use it for simple tasks, everything is fine.&lt;/p&gt;

&lt;p&gt;But if you have a monorepo project structure with packages and apps, you have to run a lot of iterations to complete tasks. Even if the rules and skills specify the project structure — where types, helpers, and ESLint configurations are located — it still doesn't follow that structure. And it's very slow compared to Sonnet, and it's about 20 times slower than GPT-5.6. I asked the agent with MiniMax to copy the structure from another monorepo repository, and it took me 4 hours of back-and-forth with the agent to clarify the details so that it would finally complete the task. With Claude Sonnet 5, this takes me about 15–30 minutes.&lt;/p&gt;

&lt;p&gt;Benchmarks and real-world performance differ greatly. If a model is estimated to be close to Sonnet or even Opus in benchmarks, in practice there may be a significant gap between them.&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;h2&gt;
  
  
  Pricing and Value
&lt;/h2&gt;

&lt;p&gt;You need to consider not only quality and speed, but also price. MiniMax is 10 times cheaper than Claude Sonnet 5. A $10 subscription gives you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;1,500 queries every 5 hours&lt;/li&gt;
&lt;li&gt;15,000 queries per week&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I also noticed that MiniMax's planning capabilities are quite good — comparable to Sonnet or GPT. Therefore, for simple tasks or situations where speed isn't a priority, MiniMax can be a reasonable choice.&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;My Blog: &lt;a href="https://orchidfiles.com/" rel="noopener noreferrer"&gt;orchidfiles.com&lt;/a&gt;&lt;br&gt;
Telegram Channel: &lt;a href="https://t.me/orchidfiles" rel="noopener noreferrer"&gt;@orchidfiles&lt;/a&gt;&lt;/p&gt;

</description>
      <category>cursor</category>
      <category>minimax</category>
      <category>ai</category>
      <category>opensource</category>
    </item>
    <item>
      <title>How to use Claude and ChatGPT subscriptions in Cursor instead of paying for API tokens</title>
      <dc:creator>Orchid Files</dc:creator>
      <pubDate>Thu, 02 Apr 2026 07:53:12 +0000</pubDate>
      <link>https://dev.to/orchidfiles/how-to-use-a-claude-subscription-in-cursor-without-paying-for-api-tokens-1bfa</link>
      <guid>https://dev.to/orchidfiles/how-to-use-a-claude-subscription-in-cursor-without-paying-for-api-tokens-1bfa</guid>
      <description>&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; Claude and ChatGPT subscriptions can be used in Cursor through OAuth login and a local proxy exposed via a Cloudflare tunnel — no API tokens needed. The open-source extension automates the whole flow: login, proxy, and tunnel are handled in one minute. Install and configure it: &lt;a href="https://github.com/orchidfiles/ungate" rel="noopener noreferrer"&gt;https://github.com/orchidfiles/ungate&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;In Cursor, you can connect any LLM via API that is compatible with the OpenAI request format. However, if you have a Claude or ChatGPT subscription, you won't be able to use them directly in Cursor. Their request formats differ from the OpenAI API format, so you'll need a workaround — proxying the requests.&lt;/p&gt;

&lt;p&gt;There are already solutions on GitHub that convert the OpenAI format to the provider's required format and back. But to add this to Cursor, simply running the process on localhost and adding it to Cursor is not enough, because Cursor first sends requests to its own backend, and from there to an OpenAI-compatible API. If you add localhost there, their backend simply won't be able to reach it. That's why you need to set up a tunnel that forwards traffic to your localhost. Cloudflare is very well suited for this. With the &lt;code&gt;cloudflared tunnel&lt;/code&gt; command, you can start a tunnel and add the tunnel address to Cursor.&lt;br&gt;
&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;
  
  
  Ungate
&lt;/h2&gt;

&lt;p&gt;Ungate is an open-source Cursor extension that connects your Claude or ChatGPT subscription to Cursor's native chat. You log in via OAuth in your browser, the extension runs a local proxy that converts the request formats, and it sets up a Cloudflare tunnel automatically. The whole setup takes one minute.&lt;/p&gt;

&lt;p&gt;Most existing solutions retrieve the Claude subscription token in two ways. The first method works only if you already have the Claude CLI installed and are logged in to it. It retrieves the token that the Claude CLI has stored on your system. The second method is not tied to the Claude CLI and allows you to log in to Claude in your browser using OAuth and add the token.&lt;/p&gt;

&lt;p&gt;These solutions do not support everything required for development. In some of them, only chat is proxied properly, while tool use, such as modifying files or using planning mode, is not supported. Others support only some tools, but not all of them. In some cases, only Claude is supported, and ChatGPT does not work.&lt;/p&gt;

&lt;p&gt;I took the best features from these solutions, added support for all tools, and created a Cursor extension:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;OAuth login for Claude and ChatGPT, no CLI required&lt;/li&gt;
&lt;li&gt;Full tool support: chat, file edits, planning mode&lt;/li&gt;
&lt;li&gt;Automatic Cloudflare tunnel — no manual &lt;code&gt;cloudflared&lt;/code&gt; setup&lt;/li&gt;
&lt;li&gt;Dashboard with request statistics and logs&lt;/li&gt;
&lt;li&gt;Auto-fix for Cursor silently disabling the custom Base URL setting&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The entire setup takes just one minute, and you can use your subscriptions in Cursor instead of paying for API tokens.&lt;/p&gt;

&lt;p&gt;GitHub: &lt;a href="https://github.com/orchidfiles/ungate" rel="noopener noreferrer"&gt;https://github.com/orchidfiles/ungate&lt;/a&gt;&lt;br&gt;
&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;
  
  
  Claude vs ChatGPT subscriptions in Cursor
&lt;/h2&gt;

&lt;p&gt;Both subscriptions work through the same proxy flow, so the choice mostly comes down to models. Claude keeps its token refreshed automatically. ChatGPT needs re-authorization via OAuth every few weeks — until you do it, requests will fail with an error.&lt;/p&gt;

&lt;p&gt;Beyond that, the difference is the models themselves. Any Claude model is available via a custom model ID, and the same applies to GPT models.&lt;/p&gt;

&lt;p&gt;The economics are straightforward:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A $20 ChatGPT subscription gives access to ~$1,000 worth of tokens&lt;/li&gt;
&lt;li&gt;A $100 Claude subscription gives access to ~$2,000 worth of tokens&lt;/li&gt;
&lt;li&gt;Total cost: $20 for a Cursor subscription plus your existing provider subscription — instead of paying for API tokens&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can also connect both subscriptions at the same time and switch between them in the same chat.&lt;br&gt;
&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;
  
  
  Official extensions vs Ungate
&lt;/h2&gt;

&lt;p&gt;Anthropic ships its own Claude Code extension for Cursor (&lt;code&gt;anthropic.claude-code&lt;/code&gt;). OpenAI ships a mirror one — the Codex extension (&lt;code&gt;openai.chatgpt&lt;/code&gt;). Both are official, and both work differently from Ungate:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspect&lt;/th&gt;
&lt;th&gt;Official extensions (Claude Code, Codex)&lt;/th&gt;
&lt;th&gt;Ungate&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Where requests run&lt;/td&gt;
&lt;td&gt;A separate agent panel with its own UI, context, and history&lt;/td&gt;
&lt;td&gt;The native Cursor chat: Chat, Agent, and Composer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Providers&lt;/td&gt;
&lt;td&gt;One provider per extension — Claude Code only works with Claude, Codex only with GPT&lt;/td&gt;
&lt;td&gt;Claude and ChatGPT subscriptions in one place&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Model picker&lt;/td&gt;
&lt;td&gt;Only the models of that one provider&lt;/td&gt;
&lt;td&gt;Any Claude or GPT model, switch providers in one place&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Setup&lt;/td&gt;
&lt;td&gt;The official extension/CLI plus the matching subscription&lt;/td&gt;
&lt;td&gt;OAuth login in browser, one minute total&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cursor UX&lt;/td&gt;
&lt;td&gt;Separate workflow, separate diff review&lt;/td&gt;
&lt;td&gt;Native Cursor diffs, context, and tools&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The official extensions put a second agent with its own workflow next to Cursor — Claude Code locked to Claude, Codex locked to GPT. Ungate does the opposite: it routes requests through your subscription inside the native Cursor interface, so you keep the model picker, diff review, and context you already know — and you can use the same setup for both Claude and ChatGPT.&lt;/p&gt;

&lt;p&gt;In practice this means a workflow that no official extension can offer: ask GPT through your subscription to write a solution, then ask Claude through your subscription to review the result in the same chat. When you're ready to implement, toggle proxying off with one button right below the chat, switch to Cursor's Composer, and later turn proxying back on to have GPT or Claude check the changes.&lt;br&gt;
&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;p&gt;You can install the extension from the Extensions panel in Cursor by searching for &lt;code&gt;@id:orchidfiles.ungate&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Installation from the terminal: &lt;code&gt;cursor --install-extension orchidfiles.ungate&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;You can also compile the extension from source:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/orchidfiles/ungate.git
&lt;span class="nb"&gt;cd &lt;/span&gt;ungate
pnpm &lt;span class="nb"&gt;install
&lt;/span&gt;pnpm run package:build
cursor &lt;span class="nt"&gt;--install-extension&lt;/span&gt; &lt;span class="s2"&gt;"apps/extension/out/ungate.vsix"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After installing the extension in Cursor, a button labeled &lt;code&gt;Ungate: API running | Tunnel stopped&lt;/code&gt; appears in the status bar. It means the proxy service is running and the tunnel is paused. Clicking it opens the Dashboard with proxied request statistics and settings. In Settings, you can change the port, restart the tunnel, log in to Claude and ChatGPT via OAuth, and view the tunnel and proxy logs.&lt;br&gt;
&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Initial setup:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Start a tunnel in the dashboard and get the URL from Cloudflare.&lt;/li&gt;
&lt;li&gt;Paste this URL into &lt;code&gt;Cursor Settings -&amp;gt; Models -&amp;gt; API Keys -&amp;gt; Override OpenAI Base URL&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Copy the API Key from the dashboard and paste it into &lt;code&gt;Cursor Settings -&amp;gt; Models -&amp;gt; API Keys -&amp;gt; OpenAI API Key&lt;/code&gt;. This is not your subscription key, but the API key for the proxying service, so that other people cannot make requests to your localhost. It's generated when the extension is installed.&lt;/li&gt;
&lt;li&gt;Copy the ID of the desired model and add a custom model in Cursor using that exact name.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Once you've done this, you can select this model in Cursor chat, and all requests will be routed through your subscription.&lt;/p&gt;

&lt;p&gt;The extension has a quick actions menu. When you hover over the extension in the status bar, a tooltip will appear. In it, you can restart the tunnel, copy the tunnel address, and toggle request proxying.&lt;br&gt;
&amp;nbsp;&lt;/p&gt;

&lt;h2&gt;
  
  
  Issues, Limits, and Notes
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Cursor automatically disables the custom OpenAI Base URL setting every few hours, causing all requests to go through API tokens again. This "bug" has existed for a very long time, and they haven't fixed it. I think it's not economically viable for them to fix this bug. The extension automatically checks whether this setting is enabled. When Cursor unchecks this, the extension re-enables it.&lt;/li&gt;
&lt;li&gt;Standard model names in Cursor only work for certain providers. For example, if you send a request using the built-in GPT-5.4 model, the request will go through the proxy using your subscription. But if you use Sonnet 4.7, the request will go through the API to Claude using tokens. In the extension, you can create custom model names and add them to Cursor so that requests are guaranteed to go through the proxy.&lt;/li&gt;
&lt;li&gt;To avoid releasing a new extension for every version of Node and OS, the extension downloads the better-sqlite3 and cloudflared builds from their repositories during the initial installation.&lt;/li&gt;
&lt;li&gt;If you disconnect your laptop from the internet and then reconnect, you need to restart the tunnel. If you see "Reconnecting..." when making a request in the chat, you need to restart the tunnel.&lt;/li&gt;
&lt;li&gt;If you receive a 401 error when making requests, it means you have an incorrect API key. You need to go to the extension's Dashboard, copy the api-key, and paste it into &lt;code&gt;Cursor Settings -&amp;gt; Models -&amp;gt; API Keys -&amp;gt; OpenAI API Key&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;If you receive a 404 error, it means the tunnel is not running or the tunnel address is incorrect.&lt;/li&gt;
&lt;li&gt;Automatic token refresh only works for Claude. With ChatGPT, you need to re-authorize your account via OAuth every few weeks.&lt;/li&gt;
&lt;li&gt;Your usage through the proxy counts against the same limits as your regular subscription usage. The dashboard shows proxied request statistics, so you can track consumption. If you hit a limit, the provider throttles or blocks requests until the usage window resets.&lt;/li&gt;
&lt;li&gt;Using a subscription outside official clients sits in a gray zone. Anthropic updated its terms in February 2026 to prohibit extracting OAuth tokens outside the official Claude Code client; OpenAI has similar restrictions. I have been using this setup for over six months without account issues, but that is not a guarantee. Use it at your own risk — the code is open source, so you can audit exactly what it does.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If something does not work in the extension, or if you have any questions, please create an issue on GitHub or write here in the comments. Contributions are welcome: open a pull request if you want to improve the code — I review all PRs within 24 hours and either merge them or leave comments.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://orchidfiles.com/" rel="noopener noreferrer"&gt;Blog&lt;/a&gt; • &lt;a href="https://t.me/orchidfiles" rel="noopener noreferrer"&gt;Telegram channel&lt;/a&gt;&lt;/p&gt;

</description>
      <category>cursor</category>
      <category>claude</category>
      <category>chatgpt</category>
      <category>ai</category>
    </item>
    <item>
      <title>PM2 has no web UI. Every open source alternative is dead. So I built one.</title>
      <dc:creator>Orchid Files</dc:creator>
      <pubDate>Wed, 18 Mar 2026 18:11:06 +0000</pubDate>
      <link>https://dev.to/orchidfiles/pm2-has-no-web-ui-every-open-source-alternative-is-dead-so-i-built-one-4ej3</link>
      <guid>https://dev.to/orchidfiles/pm2-has-no-web-ui-every-open-source-alternative-is-dead-so-i-built-one-4ej3</guid>
      <description>&lt;h2&gt;
  
  
  Why I started this project
&lt;/h2&gt;

&lt;p&gt;PM2 is the most popular process manager for Node.js, with 2 million downloads per week, but it's provided as a CLI tool. If you want to view processes in a browser, manage them, and receive notifications via Slack or email, you need to use PM2 Plus. This is a paid, subscription-based cloud service.&lt;/p&gt;

&lt;p&gt;All open-source alternatives are built using JS+HTML. They lack modules, type safety, tests, and an architecture designed for extensibility. They are difficult to maintain and develop. You can't simply fork them and add new features without rewriting most of the code. And since they lack tests, you can break anything with your changes.&lt;/p&gt;

&lt;p&gt;Almost all open-source solutions have been abandoned. The most popular ones, based on star count, haven't been updated in 2 to 10 years. Some have issues that have been open for years, and pull requests aren't accepted. The authors have abandoned these projects. Yet new repositories pop up every few months, but they're still just plain JS with a single routes file and a few pages on the frontend. Without any well-thought-out architecture.&lt;/p&gt;

&lt;p&gt;I've been using pm2 for about 10 years now, and I've wanted to create a pm2 dashboard for a long time. AI agents make this kind of project much faster to build. That doesn't mean this is just some vibe-coding project where I simply asked the AI to create a dashboard and dumped the code into Git. I make 100% of the architectural decisions, review 100% of the code, and I write each new task for it in a new chat. The AI agent doesn't make decisions; it only handles the routine tasks: writing code, tests, and markup.&lt;/p&gt;

&lt;p&gt;Fun fact. When I started brainstorming a name for the npm package, I went through dozens of options and settled on &lt;code&gt;pm2-dashboard&lt;/code&gt;. It had been taken by an inactive package for 11 years and became available 11 days before I started choosing a project name. I managed to grab it and publish a placeholder. It seems like a huge coincidence that the best possible name for the project became available at just the right moment.&lt;/p&gt;




&lt;h2&gt;
  
  
  How the project is structured
&lt;/h2&gt;

&lt;p&gt;I decided to build a project that would be very easy to extend and maintain — with full TypeScript coverage, test coverage, linters, and a modular architecture. For the structure, I chose a monorepo approach: apps, packages, scripts, and docs. As usual, packages/shared contains shared modules, constants, types, and helpers.&lt;/p&gt;

&lt;p&gt;For the frontend, I chose between Vue, React, and Svelte. I'm familiar with all of them, but I chose Svelte because I prefer its style over React's, and I haven't worked with Vue in a long time. Fewer developers are familiar with it, which might complicate maintenance, but if you work with AI agents and know Tailwind, there won't be any issues.&lt;/p&gt;

&lt;p&gt;On the backend, I immediately chose NestJS for its dependency injection and modular architecture; it's better for scalability than Express or Fastify. I also considered AdonisJS, but it's less popular. It might take longer to set up initially, but I simply asked an AI agent to port the existing NestJS code from my other projects. But it pays off in both maintenance and extensibility.&lt;/p&gt;

&lt;p&gt;For the database, I chose between PostgreSQL and SQLite. I chose SQLite because so the package can be installed with a single command from npm, and there's no need to spin up a Docker container for the database — the entire database is in a single file. For the ORM, I chose between TypeORM and Drizzle. I chose Drizzle because I hadn't worked with it yet and wanted to gain some experience, and it seems like most new projects are choosing it now.&lt;/p&gt;

&lt;p&gt;Between JWT and cookie-based sessions, I chose the latter because JWT offers no advantages for a self-hosted tool with a few users, but it complicates logout and token deletion. Surprisingly, I couldn't find a library that works with &lt;code&gt;express-session&lt;/code&gt; and &lt;code&gt;better-sqlite3&lt;/code&gt; and writes sessions to the same database file. &lt;code&gt;connect-sqlite3&lt;/code&gt; writes sessions to a separate file, and &lt;code&gt;better-sqlite3-session-store&lt;/code&gt; has a license incompatible with MIT. I built my own session solution in 30 lines of code.&lt;/p&gt;

&lt;p&gt;On first launch, a setup wizard appears, prompting you to create a user; after that, access to the interface is available only via username and password. No .env or other configuration files.&lt;/p&gt;

&lt;p&gt;It took 5 days from the project idea to a working version and writing this post. Without AI agents, it would have taken much longer. And without AI agents, I probably wouldn't have even started this project.&lt;/p&gt;




&lt;h2&gt;
  
  
  What's already working
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;List of processes with CPU, RAM, and status&lt;/li&gt;
&lt;li&gt;Start, stop, and restart for each process, as well as bulk operations&lt;/li&gt;
&lt;li&gt;Uptime and restart counters&lt;/li&gt;
&lt;li&gt;Authentication&lt;/li&gt;
&lt;li&gt;Setup wizard on first launch&lt;/li&gt;
&lt;li&gt;A single npm package with API and web interface&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Next priorities
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Real-time updates via WebSocket&lt;/li&gt;
&lt;li&gt;Log viewer&lt;/li&gt;
&lt;li&gt;Metrics history with graphs&lt;/li&gt;
&lt;li&gt;Alerts&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  How to try it
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx pm2-dashboard
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It will open at &lt;code&gt;http://localhost:3000&lt;/code&gt;. On first run, the CLI prints a setup link.&lt;/p&gt;

&lt;p&gt;GitHub: &lt;a href="https://github.com/orchidfiles/pm2-dashboard" rel="noopener noreferrer"&gt;https://github.com/orchidfiles/pm2-dashboard&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Beyond technical posts, I write essays and short observations on &lt;a href="https://orchidfiles.com/" rel="noopener noreferrer"&gt;orchidfiles.com&lt;/a&gt; and &lt;a href="https://t.me/orchidfiles" rel="noopener noreferrer"&gt;Telegram&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>node</category>
      <category>devops</category>
      <category>opensource</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Stigma is a tax on every operational decision</title>
      <dc:creator>Orchid Files</dc:creator>
      <pubDate>Sat, 14 Mar 2026 10:43:00 +0000</pubDate>
      <link>https://dev.to/orchidfiles/stigma-is-a-tax-on-every-operational-decision-4lpm</link>
      <guid>https://dev.to/orchidfiles/stigma-is-a-tax-on-every-operational-decision-4lpm</guid>
      <description>&lt;p&gt;If you are planning to create an online casino or a copy of OnlyFans, you most likely want to get in quickly, make money fast, and get out. You are unlikely to stick with it for 10 years. Just as many criminals hope to pull off one last heist, earn a living, and never do it again. The idea of one last job sounds heroically romantic.&lt;/p&gt;

&lt;p&gt;Working on an 18+ project feels like being a rock star. You work with 18+ content, see the audience, see the performers, and get access to what feels like something secret. Some see it as excitement, risk, drama, and a feeling of being alive. And then it turns out that stigma is built into almost every operational decision: hiring, advertising, payments, investments, social circle, and reputation. Stigma is the price you pay for permission to exist.&lt;/p&gt;

&lt;p&gt;You may have a cool product in the field of sports betting, casinos, or lotteries. But almost all social networks and search engines won’t let you advertise without a license from the required jurisdiction. Finding investment for such projects is far harder than for conventional niches. Do you want to build an AI-powered 18+ video generator? When posting job openings, you will always have to beat around the bush, without using direct language. And only then, when the candidate has already agreed to an interview or even after it, do you tell them what kind of content they will be working with every day.&lt;/p&gt;

&lt;p&gt;Employees join such projects for various reasons. Some realize that the pay is better than in legitimate projects. Others come because they couldn’t find a job where they wanted to, or because they are simply interested in working on something forbidden. And then a good company saving the world will come along and offer them a job, and they’ll leave. Building a stable team from people with this kind of motivation is hard.&lt;/p&gt;

&lt;p&gt;Payment providers, including Stripe, do not work with 18+ and gambling. You will have to look for others. A regular provider charges a regular commission but will not work with you, while another will want a commission 10 times higher and will agree, but may stop working with you at any time. These are often unreliable providers who are willing to work with risky categories. Or you will have to give up payment providers altogether, accept only cryptocurrency, and set up the processing yourself, because even many crypto processors prohibit these categories. Your creatives won’t pass moderation on ad networks. Accounts will be blocked for advertising prohibited projects. You need constant account warming, proxies, anti-detect browsers, moderation bypasses, and cycling through accounts. All of this takes a lot of time and money. Venture investors refuse to fund such projects, so they are often financed with personal money or money from friends. There are few who want to hedge their portfolio or just dabble in this space because it gets their blood pumping too.&lt;/p&gt;

&lt;p&gt;Formal rules and legal protection mechanisms, which are common in legitimate projects, do not work well here. Many companies in these areas are not registered at all. They operate through nominees, without an office, without official salaries, and without paying taxes. When the business itself is illegal, the courts and police no longer seem like a natural means of protection. So competitors resort to spam, DDoS attacks, data leaks, hacking, fake reviews, and reputation damage. If your company also operates unofficially and your competitors want to eliminate you, they will not be able to do so officially and will look for other ways. And they may find them.&lt;/p&gt;

&lt;p&gt;This kind of business can’t make you proud if you’re not in an environment that appreciates it. If all your friends go to church on Sundays or your wife is an elementary school teacher, they’re not likely to approve of a webcam studio business. Your other half will feel uncomfortable talking about what you do. She won’t talk about it with her friends or at work parties. This will constantly weigh on you, even if you don’t notice it at first. Your religion or the religion of those around you may also disapprove. Life is not what happens to you, but what you are able to talk about. But if the product becomes successful, how will you talk about it to your friends? If you built the best casino site, it feels like you are participating in the decay of society and are proud of it.&lt;/p&gt;

&lt;p&gt;Or you have a traffic arbitrage project: you buy traffic on Google and use cloaking to direct it to casino sites via referral links. You find an excuse: if it weren’t for you, someone else would be doing it. You’re not stealing money from a card, you’re just connecting a Google search to a casino site, and then the person loses tens of thousands of dollars themselves. You don’t force the person to make a deposit, you don’t take money from their card, you don’t gamble their money away. It’s like you’re not to blame. People gamble at casinos, but society shifts the blame onto those who build a business on it. When a person tries to find excuses for their actions, it means they feel uncomfortable but keep going. In niches without stigma, such rationalizations are unnecessary.&lt;/p&gt;

&lt;p&gt;Success in a stigmatized niche rarely translates into reputation beyond it. You’ve built a product with a million users, but you can’t always add this project to LinkedIn without damaging your reputation. You spent 5 years, achieved significant revenue, somehow assembled a team and pay them well above market rates so that people don’t leave for a more legitimate project, made contacts in related projects, analyzed your competitors, and know this market well. And the better you made the product, the more you are tied to a niche that is difficult to leave.&lt;/p&gt;




&lt;p&gt;Blog: &lt;a href="https://orchidfiles.com/" rel="noopener noreferrer"&gt;orchidfiles.com&lt;/a&gt;&lt;br&gt;
Telegram channel: &lt;a href="https://t.me/orchidfiles" rel="noopener noreferrer"&gt;@orchidfiles&lt;/a&gt;&lt;br&gt;
Email: &lt;a href="mailto:orchid@orchidfiles.com"&gt;orchid@orchidfiles.com&lt;/a&gt;&lt;br&gt;
Telegram DM: &lt;a href="https://t.me/askorchid" rel="noopener noreferrer"&gt;@askorchid&lt;/a&gt;&lt;/p&gt;

</description>
      <category>startup</category>
      <category>entrepreneurship</category>
      <category>hiring</category>
      <category>career</category>
    </item>
    <item>
      <title>AI will build your roadmap in 10 seconds</title>
      <dc:creator>Orchid Files</dc:creator>
      <pubDate>Tue, 24 Feb 2026 00:00:00 +0000</pubDate>
      <link>https://dev.to/orchidfiles/ai-will-build-your-roadmap-in-ten-seconds-3apd</link>
      <guid>https://dev.to/orchidfiles/ai-will-build-your-roadmap-in-ten-seconds-3apd</guid>
      <description>&lt;p&gt;You can ask AI to think and plan, for example, to draw up a marketing plan for a project. And it will “think” and compose a beautiful text with arguments, breaking the plan down into stages, phases, periods, and categories. But this plan will have nothing to do with reality.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;&lt;em&gt;Build a 7-year growth roadmap for my project&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Phase 1 (0-6 months): launch, first 100 users from personal network and early adopters&lt;br&gt;
Phase 2 (6-12 months): organic growth, 500-1,000 users, early feedback and product iterations&lt;br&gt;
Phase 3 (1-2 years): product-market fit, 3-5K users, introduce paid acquisition channels&lt;br&gt;
Phase 4 (2-4 years): scaling, 10-30K users, achieve sustainable revenue&lt;br&gt;
Phase 5 (4-7 years): maturity, 50-100K users, expand into adjacent markets and segments&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;How many downloads will my app get after launch?&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Pessimistic: 100-500 in the first month&lt;br&gt;
Realistic: 1,000-3,000 in the first month&lt;br&gt;
Optimistic: 10,000+ in the first month&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;How do I attract the first users to my product?&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;Create an account on Twitter/X and start posting build-in-public content&lt;/li&gt;
&lt;li&gt;Write an article on Hacker News&lt;/li&gt;
&lt;li&gt;Launch on Product Hunt&lt;/li&gt;
&lt;li&gt;Start a free newsletter with valuable content&lt;/li&gt;
&lt;li&gt;Find 10 relevant communities on Reddit and become an active participant&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;




&lt;p&gt;These answers are equally useless. Even if you provide him with the context of the project and the decisions made earlier, he still won’t be able to think. He will only write a plausible plan. In reality, you’ll find that posts on HN rarely make it to the front page, there is no one to send the newsletter to, X hardly ever generates clicks on external links, and Reddit bans self-promotion.&lt;/p&gt;

&lt;p&gt;He can convince you that your startup is definitely a blue ocean and your key feature is your product-market fit. But the future is stochastic. AI models cannot predict it. His pessimistic predictions are never zero. Most likely because the training data in such predictions most often does not have zero. Although if you ask him, “But there could be zero users in a year, right?”, he will agree with that. His predictions are just another way of saying “I don’t know”.&lt;/p&gt;

&lt;p&gt;Planning with AI is almost no different from planning by an incompetent person. A person without AI can draw up the same plan. But in most cases, whether it’s planned by a person or AI, the plan will not survive the collision with reality. People have always passed off plausible text about the future as forecasts. AI has simply accelerated this. Previously, it was expensive and time-consuming, so it seemed valuable. Now AI generates the same plausible plan in 10 seconds, and it becomes clear that the emperor has no clothes.&lt;/p&gt;




&lt;p&gt;My &lt;a href="https://orchidfiles.com/" rel="noopener noreferrer"&gt;blog&lt;/a&gt; has all of my essays and notes, and I also write on &lt;a href="https://t.me/orchidfiles" rel="noopener noreferrer"&gt;Telegram&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Email: &lt;a href="mailto:orchid@orchidfiles.com"&gt;orchid@orchidfiles.com&lt;/a&gt; · Telegram: &lt;a href="https://t.me/askorchid" rel="noopener noreferrer"&gt;@askorchid&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>startup</category>
      <category>planning</category>
      <category>entrepreneurship</category>
    </item>
    <item>
      <title>Startups remember backups after the crash</title>
      <dc:creator>Orchid Files</dc:creator>
      <pubDate>Wed, 11 Feb 2026 00:47:22 +0000</pubDate>
      <link>https://dev.to/orchidfiles/building-is-easy-preserving-requires-care-4oak</link>
      <guid>https://dev.to/orchidfiles/building-is-easy-preserving-requires-care-4oak</guid>
      <description>&lt;p&gt;In startups, something often seems more urgent than backups: a new release, user growth, the next round of funding. When resources are scarce, the team focuses on building the product, not the infrastructure. And every day, shipping wins. Backups keep getting postponed. Not just because there’s no time, but because thinking about them means admitting how fragile everything is, and how much rests on the people behind it. In the early stages, it’s often just a single backup. No automation, no established processes. Beneath it lies a quiet belief that disasters happen to others — until the first failure shatters that illusion within seconds, and you discover there are no copies, access is lost, and nothing can be recovered.&lt;br&gt;
&amp;nbsp;&lt;/p&gt;

&lt;p&gt;You don’t learn how resilient your system is until it breaks. Even the most reliable systems are not immune to rare, unpredictable events. Sometimes a single accident is enough to put everything at risk. A fire, a flood, or a lightning strike can destroy both originals and backups if they’re stored in the same place.&lt;/p&gt;

&lt;p&gt;The loss of code, documents, and databases erases not only a project’s memory but the time that went into it. It feels like everything is gone — until you manage to recover at least part of the data. What comes after is relief, and a realization of how close everything came to being lost. Sometimes recovery never comes, leaving only emptiness.&lt;br&gt;
&amp;nbsp;&lt;/p&gt;

&lt;p&gt;After something like this, you never think about your systems the same way. It’s the point where a founder starts caring not just about growth, but about what’s already running. Making a backup means accepting that the system is vulnerable. But at least you’ve done something about it. It brings back a sense of control that’s easy to lose when you’re focused on shipping.&lt;/p&gt;

&lt;p&gt;Catastrophes don’t start in code; they start in the decisions around it — running the wrong command, deleting the wrong file, acting in moments of haste or fatigue. One mistake can erase years of work. Sometimes it’s human error; sometimes it’s a system we trusted too much. Technology creates the illusion of safety: when everything is stored in the cloud or syncs automatically, it instills confidence that nothing will go wrong. As long as it works, we think we’re in control. But any protection weakens the moment it stops being tested. Panic doesn’t come from the loss itself, but from the realization that there was no plan. Security isn’t about feeling in control. It’s about having a plan for when you’re not.&lt;/p&gt;

&lt;p&gt;Data loss isn’t just a technical failure. It’s a breach of trust. Even if the data can be recovered, restoring reputation is much harder. A single failure can erase years of credibility in the eyes of investors or users.&lt;/p&gt;

&lt;p&gt;Security is a habit of taking care of what you’ve built. It doesn’t demand perfection, only attention. Imperfect protection is better than none. And a tested backup is better than the illusion of stability. Sometimes all it takes is one evening — make a backup, test restoring it, and finally sleep soundly.&lt;br&gt;
&amp;nbsp;&lt;/p&gt;

&lt;p&gt;Technology evolves. Complacency endures.&lt;br&gt;
Building something means taking responsibility for its survival.&lt;br&gt;
It’s respect for time that can never be regained.&lt;/p&gt;




&lt;p&gt;All of my essays are available on my &lt;a href="https://orchidfiles.com/" rel="noopener noreferrer"&gt;blog&lt;/a&gt;.&lt;br&gt;
I post notes every day on my &lt;a href="https://t.me/orchidfiles" rel="noopener noreferrer"&gt;Telegram channel&lt;/a&gt;.  &lt;/p&gt;

&lt;p&gt;You can reach me by &lt;a href="mailto:orchid@orchidfiles.com"&gt;email&lt;/a&gt; or on &lt;a href="https://t.me/askorchid" rel="noopener noreferrer"&gt;Telegram&lt;/a&gt;. I reply to all messages.&lt;/p&gt;

</description>
      <category>startup</category>
      <category>backups</category>
      <category>devops</category>
      <category>infrastructure</category>
    </item>
    <item>
      <title>The limits of interview questions</title>
      <dc:creator>Orchid Files</dc:creator>
      <pubDate>Sun, 08 Feb 2026 11:49:17 +0000</pubDate>
      <link>https://dev.to/orchidfiles/the-limits-of-interview-questions-33aj</link>
      <guid>https://dev.to/orchidfiles/the-limits-of-interview-questions-33aj</guid>
      <description>&lt;p&gt;When I worked as a developer and team lead, I went through a lot of interviews. Over time, I built up a list of odd and unhelpful questions. There were many, but here are the ones that stood out the most. I’m not trying to guess what the interviewers were thinking. I’m just showing how these questions sound in conversation and the impression they leave.&lt;br&gt;
&amp;nbsp;&lt;/p&gt;

&lt;h3&gt;
  
  
  The Quirky Ones
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;What’s your favorite color and why?&lt;/li&gt;
&lt;li&gt;What animal do you associate yourself with?&lt;/li&gt;
&lt;li&gt;How would you describe your perfect day?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These questions sound unusual, but they don’t tell you anything about how a person works. The answers are wide open to interpretation, so the focus shifts from real experience to guessing the right image. A candidate either recites something they’ve prepared or improvises a response, and neither option says much about how they approach problems. It’s hard to draw any conclusions about work behavior or decision-making from answers like these. More often than not, they add noise rather than help with evaluation.&lt;br&gt;
&amp;nbsp;&lt;/p&gt;

&lt;h3&gt;
  
  
  Passive-Aggressive Traps
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Aren’t you worried you won’t keep up with our pace?&lt;/li&gt;
&lt;li&gt;Don’t you think you might be overqualified for this role?&lt;/li&gt;
&lt;li&gt;How do you explain the long gaps in your career?&lt;/li&gt;
&lt;li&gt;How much were you making before?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These questions often feel like an attempt to uncover a hidden problem. They focus less on professional experience and more on external circumstances, which rarely help you understand how someone will work in a team. This stands out even more in startups. A person’s past salary doesn’t reflect their current motivation or expectations. A long career break might have nothing to do with competence. And a concern about being overqualified means nothing without context about the role. It’s easy to misread signals like these and turn down someone who might actually be a great fit.&lt;/p&gt;

&lt;p&gt;There’s one question that sits on the edge of what’s fair: “Why have you changed jobs so often?” It can be a reasonable one — if you understand that the answer often reflects the natural lifecycle of projects, not the candidate’s behavior. That’s exactly how it was in my case. I worked at startups, and most of them shut down in their first year.&lt;br&gt;
&amp;nbsp;&lt;/p&gt;

&lt;h3&gt;
  
  
  Not Quite Therapy
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;What do you think your friends would say about you?&lt;/li&gt;
&lt;li&gt;What about your personality makes you doubt yourself?&lt;/li&gt;
&lt;li&gt;How do you handle situations when things don’t go as planned?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These questions seem like an attempt to assess maturity and self-awareness. In practice, they shift the conversation into personal reflection under observation. The candidate doesn’t have time to think it through or ask for context. They came to talk about work — and suddenly they’re expected to quickly explain their own reactions and motives. Without a prepared answer, they start guessing what kind of response is expected. That forces them to improvise. In the end, the interview ends up measuring not how well they’d do the job, but how well they handle being put on the spot.&lt;br&gt;
&amp;nbsp;&lt;/p&gt;

&lt;h3&gt;
  
  
  The Culture Fit Game
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Why do you believe you’re a good fit for this role?&lt;/li&gt;
&lt;li&gt;How do you think your experience could benefit our team?&lt;/li&gt;
&lt;li&gt;Why do you want to work with us specifically?&lt;/li&gt;
&lt;li&gt;Which of our company values resonate with you?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These questions assume the candidate made a deliberate choice and took the time to learn about the company. In reality, many people apply to dozens of roles at once and only start learning the details after they get an interview. Their understanding of internal processes and values is limited, so their answers tend to reflect not a real connection with the company, but an attempt to sound motivated without much to go on. As a result, the answers come out generic and don’t say much about how the person actually works.&lt;br&gt;
&amp;nbsp;&lt;/p&gt;

&lt;h3&gt;
  
  
  The Last Job Focus
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;What kind of tasks did you handle in your last role?&lt;/li&gt;
&lt;li&gt;What challenges did you face on that project?&lt;/li&gt;
&lt;li&gt;Why did you leave that company?&lt;/li&gt;
&lt;li&gt;What was your role in the team at the time?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These questions are reasonable on their own, but interviews often end up focusing almost entirely on the candidate’s most recent project. That project might have been short, irrelevant to the role, based on a different level of responsibility, or simply untypical in terms of tasks. As a result, the conversation revolves around a fragment that says little about the candidate’s broader experience. The person may have led a larger team before, worked on a different scale, or operated in a different environment — but that gets lost if all attention goes to the last job.&lt;/p&gt;

&lt;p&gt;I’ve often tried to zoom out and explain that what matters is the full arc of experience, not just the latest entry. But the conversation kept circling back to that one last project, as if it had to explain everything. This focus skews the outcome. If the last project is an outlier — the easiest one, the least successful, or simply the odd one out — then the answers reflect a random moment in someone’s career. It’s easier to talk about, but it says very little about the actual experience.&lt;/p&gt;




&lt;p&gt;At the end of the interview, it comes down to a simple question: did you understand the person — and did they understand you?&lt;/p&gt;







&lt;p&gt;For longer reads, visit my &lt;a href="https://orchidfiles.com/" rel="noopener noreferrer"&gt;blog&lt;/a&gt;.&lt;br&gt;
For daily notes, follow my &lt;a href="https://t.me/orchidfiles" rel="noopener noreferrer"&gt;Telegram channel&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you want to reach out, contact me by &lt;a href="mailto:orchid@orchidfiles.com"&gt;email&lt;/a&gt; or on &lt;a href="https://t.me/askorchid" rel="noopener noreferrer"&gt;Telegram&lt;/a&gt;. I reply to all messages.&lt;/p&gt;

</description>
      <category>career</category>
      <category>interview</category>
      <category>hiring</category>
      <category>startup</category>
    </item>
  </channel>
</rss>
