<?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: Nika Kudukhashvili</title>
    <description>The latest articles on DEV Community by Nika Kudukhashvili (@kuduxaaa).</description>
    <link>https://dev.to/kuduxaaa</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%2F574880%2F604f38fb-3c36-47b5-abae-abfe94de99f9.jpeg</url>
      <title>DEV Community: Nika Kudukhashvili</title>
      <link>https://dev.to/kuduxaaa</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kuduxaaa"/>
    <language>en</language>
    <item>
      <title>I built DeepWrap: a Python SDK and CLI for DeepSeek Chat</title>
      <dc:creator>Nika Kudukhashvili</dc:creator>
      <pubDate>Wed, 27 May 2026 20:15:21 +0000</pubDate>
      <link>https://dev.to/kuduxaaa/i-built-deepwrap-a-python-sdk-and-cli-for-deepseek-chat-3nc4</link>
      <guid>https://dev.to/kuduxaaa/i-built-deepwrap-a-python-sdk-and-cli-for-deepseek-chat-3nc4</guid>
      <description>&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%2F7q7eb0s6dgjsl7ger1z4.png" 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%2F7q7eb0s6dgjsl7ger1z4.png" alt=" " width="800" height="296"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DeepSeek Chat was free in the browser.&lt;br&gt;
But the moment I wanted to use it like a developer, it became a different story.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That annoyed me more than it probably should have.&lt;/p&gt;

&lt;p&gt;If something is usable in the browser, why should it suddenly feel blocked, awkward, or artificially expensive the moment you want to call it from Python, from your terminal, or from your own local tools?&lt;/p&gt;

&lt;p&gt;That mismatch was the whole reason I built &lt;strong&gt;DeepWrap&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;What started as “let me inspect a few requests and see how hard this is” turned into a full project: a &lt;strong&gt;Python SDK&lt;/strong&gt;, a &lt;strong&gt;terminal CLI&lt;/strong&gt;, and a &lt;strong&gt;local HTTP API wrapper&lt;/strong&gt; for DeepSeek Chat.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why I built it
&lt;/h2&gt;

&lt;p&gt;The real motivation was simple:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DeepSeek was free in the browser, but not free in the way developers actually want to use it.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;And that felt absurd.&lt;/p&gt;

&lt;p&gt;I wanted to use it in real workflows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Python scripts&lt;/li&gt;
&lt;li&gt;terminal sessions&lt;/li&gt;
&lt;li&gt;reusable chat sessions&lt;/li&gt;
&lt;li&gt;streaming responses&lt;/li&gt;
&lt;li&gt;local tools&lt;/li&gt;
&lt;li&gt;local HTTP integrations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I did not want to babysit browser tabs forever just to use a model in a developer-friendly way.&lt;/p&gt;

&lt;p&gt;So the idea behind DeepWrap was basically:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;take the browser experience and make it usable from code.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  How I built it
&lt;/h2&gt;

&lt;p&gt;At first, I genuinely thought this was going to be easy.&lt;/p&gt;

&lt;p&gt;I opened DevTools, went to the Network tab, started looking at the XHR requests, and my first thought was:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Okay, this is probably just a matter of replaying the right requests with the right headers.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That optimism did not survive very long.&lt;/p&gt;
&lt;h3&gt;
  
  
  1. Inspect the browser requests
&lt;/h3&gt;

&lt;p&gt;The first step was just observing the flow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;how a chat session gets created&lt;/li&gt;
&lt;li&gt;what headers are sent&lt;/li&gt;
&lt;li&gt;what the prompt payload looks like&lt;/li&gt;
&lt;li&gt;how the response stream comes back&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At a glance, the flow looked simple:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;create a session&lt;/li&gt;
&lt;li&gt;send a prompt&lt;/li&gt;
&lt;li&gt;read the stream&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That was enough to sketch the basic client structure.&lt;/p&gt;
&lt;h3&gt;
  
  
  2. Hit the first wall: PoW + WASM
&lt;/h3&gt;

&lt;p&gt;Then came the first real problem: &lt;strong&gt;proof-of-work&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Some requests were not just normal authenticated calls. The browser had to solve a PoW challenge, and that logic was implemented with &lt;strong&gt;WASM&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;So the project instantly got more interesting.&lt;/p&gt;

&lt;p&gt;Instead of only replaying requests, I had to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;inspect how the challenge is fetched&lt;/li&gt;
&lt;li&gt;understand the challenge payload&lt;/li&gt;
&lt;li&gt;find where the browser solves it&lt;/li&gt;
&lt;li&gt;reverse the WASM input/output behavior&lt;/li&gt;
&lt;li&gt;replicate the solve step from Python&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That was the point where this stopped being a “quick wrapper.”&lt;/p&gt;
&lt;h3&gt;
  
  
  3. Add auth that feels usable
&lt;/h3&gt;

&lt;p&gt;I also didn’t want the whole thing to rely only on pasting bearer tokens manually.&lt;/p&gt;

&lt;p&gt;Yes, that works.&lt;br&gt;
No, that doesn’t feel great.&lt;/p&gt;

&lt;p&gt;So I added &lt;strong&gt;browser-based auth&lt;/strong&gt; too.&lt;/p&gt;

&lt;p&gt;That meant building a flow that could:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;launch a browser&lt;/li&gt;
&lt;li&gt;connect through DevTools / remote debugging&lt;/li&gt;
&lt;li&gt;observe authenticated traffic&lt;/li&gt;
&lt;li&gt;extract the bearer token&lt;/li&gt;
&lt;li&gt;normalize it&lt;/li&gt;
&lt;li&gt;reuse it for the SDK and CLI&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That part was messy, but necessary if I wanted the project to feel real.&lt;/p&gt;
&lt;h3&gt;
  
  
  4. Parse the stream properly
&lt;/h3&gt;

&lt;p&gt;Once auth and PoW worked, I still had to handle the actual chat stream.&lt;/p&gt;

&lt;p&gt;And it was not just “text in, text out.”&lt;/p&gt;

&lt;p&gt;The stream included:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;thinking fragments&lt;/li&gt;
&lt;li&gt;response fragments&lt;/li&gt;
&lt;li&gt;partial updates&lt;/li&gt;
&lt;li&gt;metadata events&lt;/li&gt;
&lt;li&gt;close events&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So I built a parser that could:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;preserve multi-turn state&lt;/li&gt;
&lt;li&gt;keep track of &lt;code&gt;parent_message_id&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;support both streaming and non-streaming&lt;/li&gt;
&lt;li&gt;optionally separate thinking from final output&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That let the public API stay simple even if the internals were not.&lt;/p&gt;
&lt;h3&gt;
  
  
  5. Turn it into a real tool
&lt;/h3&gt;

&lt;p&gt;Once the Python API felt stable, I pushed it further:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;an interactive CLI&lt;/li&gt;
&lt;li&gt;a local FastAPI server&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So DeepWrap gradually became three things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;a Python SDK&lt;/li&gt;
&lt;li&gt;a terminal chat interface&lt;/li&gt;
&lt;li&gt;a local HTTP API wrapper&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That was the point where it stopped feeling like a hack and started feeling like a product.&lt;/p&gt;
&lt;h2&gt;
  
  
  What using it looks like
&lt;/h2&gt;

&lt;p&gt;If you just want to try it, the flow is simple.&lt;/p&gt;
&lt;h3&gt;
  
  
  Install
&lt;/h3&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;deepwrap
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Create a client
&lt;/h3&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;deepwrap&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Client&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;If you already have a token configured, that’s enough.&lt;/p&gt;
&lt;h3&gt;
  
  
  Create a chat session
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;chat&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chats&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_session&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;expert&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Send a normal response
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;respond&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Explain quantum computing in one short sentence.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;thinking&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;search&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Stream the output
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;chunk&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;respond&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Write a short explanation of black holes.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;thinking&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;search&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;flush&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Keep context across turns
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;respond&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;My name is Nika.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;respond&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;What is my name?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;That works because the session keeps track of the conversation state internally.&lt;/p&gt;
&lt;h2&gt;
  
  
  CLI usage
&lt;/h2&gt;

&lt;p&gt;I also wanted it to feel good in the terminal.&lt;/p&gt;

&lt;p&gt;You can start the interactive interface with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;deepwrap
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or use one-shot terminal calls:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;deepwrap chat &lt;span class="s2"&gt;"Explain recursion in one sentence."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That was important to me because sometimes you don’t want a script — you just want a fast terminal workflow.&lt;/p&gt;

&lt;h2&gt;
  
  
  God Mode
&lt;/h2&gt;

&lt;p&gt;I also added an experimental feature called &lt;strong&gt;God Mode&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This is not some magical hidden model. It is a session-level behavior override implemented through &lt;strong&gt;prompt injection on the first user turn&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In practice, that means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;it changes how the model behaves for that session&lt;/li&gt;
&lt;li&gt;it is intentionally intrusive&lt;/li&gt;
&lt;li&gt;it can diverge from normal behavior in unpredictable ways&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I added it mostly as a developer/testing feature, not as a normal mode for everyday use.&lt;/p&gt;

&lt;p&gt;So I treat it as exactly what it is:&lt;br&gt;
&lt;strong&gt;an experimental override for controlled testing&lt;/strong&gt;, not something meant for general use.&lt;/p&gt;

&lt;h2&gt;
  
  
  Security notes
&lt;/h2&gt;

&lt;p&gt;A few important notes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Do not commit your bearer token&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Prefer environment variables or local saved config over hardcoding secrets&lt;/li&gt;
&lt;li&gt;Tokens saved by DeepWrap are stored locally in the user config directory&lt;/li&gt;
&lt;li&gt;Browser auth should only be used in environments you trust&lt;/li&gt;
&lt;li&gt;Experimental features like God Mode should be treated as development-only behavior modifiers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;DeepWrap is an unofficial wrapper, so use it responsibly.&lt;/p&gt;

&lt;h2&gt;
  
  
  GitHub
&lt;/h2&gt;

&lt;p&gt;The project is open source here:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;code&gt;https://github.com/Kuduxaaa/deepwrap&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Feedback
&lt;/h2&gt;

&lt;p&gt;This whole project started from a very simple frustration:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;“Why is it free in the browser, but awkward the moment I want to use it like a developer?”&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Then it turned into a much bigger project than I expected:&lt;br&gt;
reverse-engineering requests, dealing with PoW WASM, browser auth, session handling, streaming, CLI UX, and local API design.&lt;/p&gt;

&lt;p&gt;If you check it out, I’d genuinely love feedback on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;API design&lt;/li&gt;
&lt;li&gt;CLI UX&lt;/li&gt;
&lt;li&gt;auth flow&lt;/li&gt;
&lt;li&gt;architecture&lt;/li&gt;
&lt;li&gt;docs&lt;/li&gt;
&lt;li&gt;feature ideas&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If something feels awkward, overbuilt, underbuilt, or just weird, tell me.&lt;/p&gt;

&lt;p&gt;That kind of feedback is the most useful.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>cli</category>
      <category>python</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
