<?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: Michael Oblak</title>
    <description>The latest articles on DEV Community by Michael Oblak (@michaloblak).</description>
    <link>https://dev.to/michaloblak</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4420%2F1c985cfe-0b85-489f-8bbf-a6ca56389ec3.jpeg</url>
      <title>DEV Community: Michael Oblak</title>
      <link>https://dev.to/michaloblak</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/michaloblak"/>
    <language>en</language>
    <item>
      <title>I built a CLI that turns any website into a Unix command - here's how I bypassed Cloudflare's TLS fingerprinting</title>
      <dc:creator>Michael Oblak</dc:creator>
      <pubDate>Tue, 03 Mar 2026 13:49:13 +0000</pubDate>
      <link>https://dev.to/michaloblak/i-built-a-cli-that-turns-any-website-into-a-unix-command-heres-how-i-bypassed-cloudflares-tls-2393</link>
      <guid>https://dev.to/michaloblak/i-built-a-cli-that-turns-any-website-into-a-unix-command-heres-how-i-bypassed-cloudflares-tls-2393</guid>
      <description>&lt;p&gt;My AI agent was spending 30 seconds and 300MB of RAM to search X. Launch Chromium, navigate, wait for render, scrape the DOM. For a GET request.&lt;/p&gt;

&lt;p&gt;That felt like driving a truck to pick up a letter.&lt;/p&gt;

&lt;p&gt;So I built &lt;a href="https://github.com/jb41/web2cli" rel="noopener noreferrer"&gt;web2cli&lt;/a&gt; - a CLI where every website is a command. Direct HTTP requests, same cookies your browser uses, structured output. No browser.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fha7i4suue70re8i28ddk.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fha7i4suue70re8i28ddk.gif" alt="demo" width="1161" height="492"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;web2cli
web2cli hn top &lt;span class="nt"&gt;--limit&lt;/span&gt; 5
web2cli x search &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s2"&gt;"AI agents"&lt;/span&gt; &lt;span class="nt"&gt;--limit&lt;/span&gt; 3 &lt;span class="nt"&gt;--format&lt;/span&gt; json
web2cli discord send &lt;span class="nt"&gt;--server&lt;/span&gt; myserver &lt;span class="nt"&gt;--channel&lt;/span&gt; general &lt;span class="nt"&gt;--message&lt;/span&gt; &lt;span class="s2"&gt;"hello"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Six adapters ship today: Hacker News, X, Discord, Slack, Stack Overflow, Reddit.&lt;/p&gt;

&lt;p&gt;The concept was simple. The implementation... less so.&lt;/p&gt;

&lt;h2&gt;
  
  
  The first wall: Cloudflare's TLS fingerprinting
&lt;/h2&gt;

&lt;p&gt;Stack Overflow uses Cloudflare. My first attempt was straightforward - httpx with a Chrome User-Agent header:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;resp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;httpx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;AsyncClient&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;User-Agent&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Mozilla/5.0 ... Chrome/120.0.0.0&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="c1"&gt;# 403 Forbidden. Every time.
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Turns out Cloudflare doesn't just check your User-Agent header. It hashes your TLS ClientHello packet - the very first message in the TLS handshake, sent &lt;strong&gt;before&lt;/strong&gt; any HTTP headers. This hash is called a JA3 fingerprint.&lt;/p&gt;

&lt;p&gt;Here's the problem: Python's default TLS stack (OpenSSL) produces a JA3 fingerprint that looks nothing like Chrome's. Chrome uses BoringSSL with a specific set of cipher suites, extensions, and ALPN protocols. OpenSSL uses different ones. &lt;/p&gt;

&lt;p&gt;So Cloudflare sees:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User-Agent says:     Chrome 120
TLS fingerprint says: Python/OpenSSL
Verdict:             Bot. Blocked.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This happens during the TLS handshake - before your HTTP request is even sent. No amount of header manipulation helps.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The fix:&lt;/strong&gt; &lt;a href="https://github.com/lexiforest/curl_cffi" rel="noopener noreferrer"&gt;curl_cffi&lt;/a&gt; - Python bindings for curl-impersonate. It replaces OpenSSL with BoringSSL (Chrome's actual TLS library) and mimics the exact cipher suites, extensions, and HTTP/2 settings.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;curl_cffi.requests&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;AsyncSession&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nc"&gt;AsyncSession&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;resp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;impersonate&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;chrome&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# 200 OK. Cloudflare thinks we're Chrome.
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One line change. JA3 hash now matches real Chrome. Cloudflare lets us through.&lt;/p&gt;

&lt;h2&gt;
  
  
  The second wall: X.com's cryptographic nonces
&lt;/h2&gt;

&lt;p&gt;X was harder. Their search endpoint requires a &lt;code&gt;x-client-transaction-id&lt;/code&gt; header - a one-time cryptographic nonce that's generated by obfuscated JavaScript in the browser.&lt;/p&gt;

&lt;p&gt;You can't reuse nonces. You can't fake them. Each one is tied to the specific request method and path.&lt;/p&gt;

&lt;p&gt;The community reverse-engineered the algorithm. The flow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Fetch x.com homepage (get the base page)&lt;/li&gt;
&lt;li&gt;Fetch a specific &lt;code&gt;ondemand.s&lt;/code&gt; JavaScript bundle&lt;/li&gt;
&lt;li&gt;Initialize a transaction generator with both&lt;/li&gt;
&lt;li&gt;Generate a fresh nonce per request
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;x_client_transaction&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ClientTransaction&lt;/span&gt;

&lt;span class="n"&gt;ct&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ClientTransaction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;home_page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ondemand_js&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;nonce&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate_transaction_id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;GET&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/search&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;x-client-transaction-id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;nonce&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This nonce rotates - the JS bundle changes periodically, so you need to refresh the generator. But it beats paying $100/mo for official API access.&lt;/p&gt;

&lt;h2&gt;
  
  
  Session architecture
&lt;/h2&gt;

&lt;p&gt;Instead of managing browser profiles, web2cli stores sessions as encrypted cookie jars:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Opens real Chromium, you log in, cookies are captured&lt;/span&gt;
web2cli login x.com &lt;span class="nt"&gt;--browser&lt;/span&gt;

&lt;span class="c"&gt;# Or paste cookies manually&lt;/span&gt;
web2cli login discord &lt;span class="nt"&gt;--cookies&lt;/span&gt; &lt;span class="s2"&gt;"token=xxx"&lt;/span&gt;

&lt;span class="c"&gt;# Or use environment variables&lt;/span&gt;
&lt;span class="nv"&gt;WEB2CLI_X_COOKIES&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"auth_token=xxx; ct0=yyy"&lt;/span&gt; web2cli x search ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sessions are encrypted with Fernet (AES-128-CBC) and stored in &lt;code&gt;~/.web2cli/sessions/&lt;/code&gt;. Your credentials never leave your machine.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;--browser&lt;/code&gt; flag is the smoothest path - Playwright opens Chromium, you log in normally (password manager, 2FA, whatever), and web2cli polls for the required cookies. When they appear, it captures them and closes the browser. You don't need to know which cookies are needed - the adapter spec declares them.&lt;/p&gt;

&lt;h2&gt;
  
  
  The adapter model
&lt;/h2&gt;

&lt;p&gt;Each website is described by a YAML file that maps CLI commands to HTTP request pipelines. Most sites need zero Python code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;commands&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;search&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Search&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;tweets"&lt;/span&gt;
    &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;query&lt;/span&gt;
        &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;limit&lt;/span&gt;
        &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;
    &lt;span class="na"&gt;pipeline&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;GET&lt;/span&gt;
          &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/search&lt;/span&gt;
          &lt;span class="na"&gt;params&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;q&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;{{args.query}}"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;parse&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;json&lt;/span&gt;
          &lt;span class="na"&gt;fields&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;author&lt;/span&gt;
              &lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;$.user.screen_name"&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;text&lt;/span&gt;
              &lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;$.full_text"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For complex sites (X.com's GraphQL, SO's Cloudflare protection), you can add Python builder/parser scripts. But the goal is that adding a new site takes ~30 minutes and a YAML file.&lt;/p&gt;

&lt;h2&gt;
  
  
  Benchmarks
&lt;/h2&gt;

&lt;p&gt;These are measured, not estimated:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Task&lt;/th&gt;
&lt;th&gt;Browser automation&lt;/th&gt;
&lt;th&gt;web2cli&lt;/th&gt;
&lt;th&gt;Speedup&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Read Discord messages&lt;/td&gt;
&lt;td&gt;26s&lt;/td&gt;
&lt;td&gt;0.63s&lt;/td&gt;
&lt;td&gt;41x&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Send a Slack message&lt;/td&gt;
&lt;td&gt;35s&lt;/td&gt;
&lt;td&gt;0.60s&lt;/td&gt;
&lt;td&gt;58x&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Search X&lt;/td&gt;
&lt;td&gt;75s&lt;/td&gt;
&lt;td&gt;1.54s&lt;/td&gt;
&lt;td&gt;50x&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Search Stack Overflow&lt;/td&gt;
&lt;td&gt;41s&lt;/td&gt;
&lt;td&gt;0.65s&lt;/td&gt;
&lt;td&gt;63x&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fetch HN submissions&lt;/td&gt;
&lt;td&gt;36s&lt;/td&gt;
&lt;td&gt;1.42s&lt;/td&gt;
&lt;td&gt;25x&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For AI agents, this changes the economics completely:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Scenario&lt;/th&gt;
&lt;th&gt;Browser&lt;/th&gt;
&lt;th&gt;web2cli&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Monitor Discord (1 check/min)&lt;/td&gt;
&lt;td&gt;$2.88/day&lt;/td&gt;
&lt;td&gt;$0.002/day&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10k daily actions&lt;/td&gt;
&lt;td&gt;~$50/day&lt;/td&gt;
&lt;td&gt;~$0.01/day&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Monthly infra&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$50+/mo&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$4/mo&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  What's next
&lt;/h2&gt;

&lt;p&gt;I'm working on &lt;strong&gt;web2cli Cloud&lt;/strong&gt; - managed sessions with proxy rotation for multi-user agents. Your users click a link, log in via a sandboxed browser, your agent gets an opaque session token. No cookies touch your server.&lt;/p&gt;

&lt;p&gt;Think "OAuth for websites that don't have OAuth."&lt;/p&gt;

&lt;p&gt;The broader question I keep coming back to: how much of "web automation" actually needs a browser? For the 80% of tasks that are just "fetch data behind a login" - probably none.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/jb41/web2cli" rel="noopener noreferrer"&gt;github.com/jb41/web2cli&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Install:&lt;/strong&gt; &lt;code&gt;pip install web2cli&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;Cloud waitlist:&lt;/strong&gt; &lt;a href="https://web2cli.com" rel="noopener noreferrer"&gt;web2cli.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>cli</category>
      <category>automation</category>
    </item>
    <item>
      <title>Build, Test, and Deploy APIs with GPT-Generated Code</title>
      <dc:creator>Michael Oblak</dc:creator>
      <pubDate>Wed, 12 Apr 2023 12:14:10 +0000</pubDate>
      <link>https://dev.to/michaloblak/build-test-and-deploy-apis-with-gpt-generated-code-5c1p</link>
      <guid>https://dev.to/michaloblak/build-test-and-deploy-apis-with-gpt-generated-code-5c1p</guid>
      <description>&lt;p&gt;Hey,&lt;/p&gt;

&lt;p&gt;I've been working on a better code plugin for GPT. Here you ask GPT for what you need. Iterate by prompting, and you get deployed API endpoint which runs your code with every request. You can use any language, as it's run inside a Docker container.&lt;/p&gt;

&lt;p&gt;Check out the repo for more information - &lt;a href="https://github.com/jb41/lambdapi" rel="noopener noreferrer"&gt;https://github.com/jb41/lambdapi&lt;/a&gt;&lt;/p&gt;

</description>
      <category>gpt3</category>
      <category>api</category>
      <category>opensource</category>
      <category>llm</category>
    </item>
  </channel>
</rss>
