<?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: Nunc</title>
    <description>The latest articles on DEV Community by Nunc (@nunc).</description>
    <link>https://dev.to/nunc</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%2F156810%2Fe88f8e22-712e-4845-8662-e399d98101b2.png</url>
      <title>DEV Community: Nunc</title>
      <link>https://dev.to/nunc</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/nunc"/>
    <language>en</language>
    <item>
      <title>I Made Claude Code and Codex Argue About My Code Until They Agreed</title>
      <dc:creator>Nunc</dc:creator>
      <pubDate>Wed, 22 Jul 2026 10:48:22 +0000</pubDate>
      <link>https://dev.to/nunc/i-made-claude-code-and-codex-argue-about-my-code-until-they-agreed-1pkd</link>
      <guid>https://dev.to/nunc/i-made-claude-code-and-codex-argue-about-my-code-until-they-agreed-1pkd</guid>
      <description>&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;: I wired OpenAI's Codex CLI into Claude Code as an adversarial reviewer with a convergence loop. Then I pointed the loop at its own implementation. It failed the review three times before passing, and every single failure was a real bug. Here's the whole story, with the prompts and shell recipes you can steal.&lt;/p&gt;

&lt;h2&gt;
  
  
  The tweet that started it
&lt;/h2&gt;

&lt;p&gt;A while ago Siqi Chen posted his favorite way of working with frontier models:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;step 1. ask it to write a plan&lt;br&gt;
step 2: "please get second opinions from codex CLI using gpt-5.6-sol @ max effort and kimi CLI using kimi 3. Revise your plan with any sound findings. repeat until convergence or up to 5 rounds."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There's also a companion repo, &lt;a href="https://github.com/blader/adversarial-execution" rel="noopener noreferrer"&gt;adversarial-execution&lt;/a&gt;, which applies the same idea at the other end: before you mark work as &lt;em&gt;done&lt;/em&gt;, fresh reviewer sessions have to pass it with evidence, in a loop, until a fresh round finds nothing new.&lt;/p&gt;

&lt;p&gt;Two ideas jumped out at me:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Fresh sessions, not continuations.&lt;/strong&gt; A reviewer that already critiqued round 1 will defend its own findings in round 2. Anchoring is real for LLMs too.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;"Looks right in the code is not evidence."&lt;/strong&gt; The reviewer judges proof (test output, screenshots, command results), not vibes.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I already had a Claude Code skill that wraps the local &lt;code&gt;codex&lt;/code&gt; CLI as a second engineer: consult it read-only, delegate a fix, run a git-aware review, resume a session. All useful. All one-shot. No loop anywhere.&lt;/p&gt;

&lt;p&gt;So I asked Claude Code to study the tweet and the repo and tell me whether the skill was worth upgrading.&lt;/p&gt;

&lt;h2&gt;
  
  
  Round zero: Codex reviews the plan for using Codex better
&lt;/h2&gt;

&lt;p&gt;Claude wrote a proposal: two new modes (a plan-review convergence loop and a done-gate), plus supporting rules. Decent plan. Then came the fun part. Before touching anything, I had Claude send the proposal itself to Codex for an adversarial review, using the exact contract style the proposal was recommending.&lt;/p&gt;

&lt;p&gt;Verdict: &lt;strong&gt;FAIL. Eight gaps, seven of them major.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;And they weren't nitpicks. My three favorites:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The output capture in the &lt;em&gt;existing&lt;/em&gt; skill was broken.&lt;/strong&gt; The recipes piped &lt;code&gt;codex exec&lt;/code&gt; output through &lt;code&gt;tail -40&lt;/code&gt; and told Claude to grab the session id "from the header". But the header is at the &lt;em&gt;start&lt;/em&gt; of stdout, and &lt;code&gt;tail&lt;/code&gt; shows the end. On any long run the session id is simply gone. Better yet: this exact failure happened &lt;em&gt;during the review run itself&lt;/em&gt;. The reviewer described a bug and the run reproduced it live. The pipeline exit code was wrong too, because without &lt;code&gt;PIPESTATUS&lt;/code&gt; you get &lt;code&gt;tail&lt;/code&gt;'s exit code, not codex's.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;False convergence.&lt;/strong&gt; My loop definition said: converged when a round brings "no new sound findings, only repeats". Codex pointed out that a finding I &lt;em&gt;accepted&lt;/em&gt; but fixed incompletely would come back as a "repeat" and get waved through. A repeated unresolved finding has to stay open. And hitting the round cap needed an explicit NOT CONVERGED outcome instead of quietly presenting the last plan as final.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Windows command lines have a length limit.&lt;/strong&gt; Passing a plan, a diff, and the round history as one quoted shell argument blows past ~32k characters. Codex suggested the CLI's stdin form (&lt;code&gt;codex exec ... - &amp;lt; prompt.txt&lt;/code&gt;), which my own skill was accidentally blocking with an unconditional &lt;code&gt;&amp;lt;/dev/null&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I triaged all eight findings. All eight were sound. That triage step matters, by the way. The instruction is "revise with any &lt;em&gt;sound&lt;/em&gt; findings", not "do whatever the reviewer says". The orchestrating model stays the decision maker; the reviewer is a hostile witness, not a boss.&lt;/p&gt;

&lt;h2&gt;
  
  
  Simplify before you ship
&lt;/h2&gt;

&lt;p&gt;The revised proposal had grown formal machinery: a findings ledger with four statuses, evidence manifests with exit codes and timestamps. My actual usage is a few Codex calls per month. That's how you end up with a skill nobody follows.&lt;/p&gt;

&lt;p&gt;So I shipped a lean version instead. The concepts survived, compressed to one line each. A skill is instructions to a model, not code. The model can track a simple ledger in its head; what it needs written down are the rules it would otherwise get wrong:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Re-reviews happen in &lt;strong&gt;fresh sessions&lt;/strong&gt;, never &lt;code&gt;resume&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Adopt only &lt;strong&gt;sound&lt;/strong&gt; findings, record rejections with a reason.&lt;/li&gt;
&lt;li&gt;An adopted-but-unfixed finding &lt;strong&gt;stays open&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Cap the loop (3 rounds for plans, 2 for the done-gate), and report &lt;strong&gt;NOT CONVERGED&lt;/strong&gt; honestly if you hit it.&lt;/li&gt;
&lt;li&gt;A failed or empty run &lt;strong&gt;never counts as a round&lt;/strong&gt;, and never as a PASS.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The done-gate eats its own dog food
&lt;/h2&gt;

&lt;p&gt;New rules in place, one question left: is the upgrade itself actually done? Perfect job for the brand-new done-gate. Fresh Codex session, max reasoning effort, evidence pack attached (diffs, validator output), and a contract that forces a machine-checkable verdict:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;INTENT: PASS | FAIL - does the work satisfy the stated acceptance criteria? (evidence)
WORKS: PASS | FAIL - does it actually function, per evidence, not per code reading? (evidence)
PLAN_FIT: PASS | FAIL - does it advance the overall plan without drift? (evidence)
VERDICT: PASS only if all three are PASS, else FAIL.
GAPS: numbered with stable IDs; severity, problem, evidence, smallest fix. If none: GAPS: NONE.
IMPROVEMENTS: optional non-blocking suggestions (max 5). These never affect the verdict.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Round 1: FAIL.&lt;/strong&gt; Four gaps. The best one: I had fixed the output handling in modes 1 and 2 but not in the review and resume recipes, and my shiny new "pass long prompts via stdin" rule used a &lt;code&gt;$PROMPT_FILE&lt;/code&gt; variable that no example ever created. Copy-paste the doc as written and you'd get "No such file or directory".&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Round 2: FAIL.&lt;/strong&gt; Two gaps. One was a claim I refused to take on faith: Codex said the skill's &lt;em&gt;original&lt;/em&gt; focused-review example, &lt;code&gt;codex exec review --uncommitted "focus on error handling"&lt;/code&gt;, is an invalid invocation, because the review target flags conflict with a positional prompt. That example predated this whole upgrade. One free local test later (argument parsing fails before any model call, so it costs nothing):&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="nv"&gt;$ &lt;/span&gt;codex &lt;span class="nb"&gt;exec &lt;/span&gt;review &lt;span class="nt"&gt;--uncommitted&lt;/span&gt; &lt;span class="s2"&gt;"focus on error handling"&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; /dev/null
error: the argument &lt;span class="s1"&gt;'--uncommitted'&lt;/span&gt; cannot be used with &lt;span class="s1"&gt;'[PROMPT]'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Confirmed. A broken example had been sitting in the skill since day one, and a fresh pair of (artificial) eyes caught it on pass two.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Round 3: PASS.&lt;/strong&gt; All three dimensions, &lt;code&gt;GAPS: NONE&lt;/code&gt;, nothing reopened. Convergence, for real this time.&lt;/p&gt;

&lt;p&gt;Three rounds, three sets of genuine defects, then nothing left to find. That's exactly the behavior the pattern promises, and I got to watch it happen to my own work.&lt;/p&gt;

&lt;h2&gt;
  
  
  The pieces you can steal
&lt;/h2&gt;

&lt;p&gt;The reliable shell wrapper for non-interactive codex runs (Git Bash, works on Windows too):&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="nv"&gt;OUT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;mktemp &lt;/span&gt;codex-out-XXXX.txt&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;LOG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;OUT&lt;/span&gt;&lt;span class="p"&gt;%.txt&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.log"&lt;/span&gt;
codex &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; read-only &lt;span class="nt"&gt;--skip-git-repo-check&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="nv"&gt;model_reasoning_effort&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"xhigh"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$OUT&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; - &amp;lt; prompt.txt 2&amp;gt;&amp;amp;1 | &lt;span class="nb"&gt;tee&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$LOG&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;tail&lt;/span&gt; &lt;span class="nt"&gt;-20&lt;/span&gt;
&lt;span class="nv"&gt;RC&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PIPESTATUS&lt;/span&gt;&lt;span class="p"&gt;[0]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"rc=&lt;/span&gt;&lt;span class="nv"&gt;$RC&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-m1&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"session id"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$LOG&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$OUT&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every piece earned its place the hard way: &lt;code&gt;-o&lt;/code&gt; captures the clean final message, &lt;code&gt;tee&lt;/code&gt; keeps the full log so the session id survives, &lt;code&gt;PIPESTATUS[0]&lt;/code&gt; gets the real exit code, and the trailing &lt;code&gt;- &amp;lt; prompt.txt&lt;/code&gt; feeds a prompt of any size through stdin.&lt;/p&gt;

&lt;p&gt;The plan-review contract (the done-gate variant is above):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You are an adversarial reviewer of a PLAN (no code changes exist yet).
Judge the plan against the stated task and acceptance criteria AND against
the actual repo state (read the code the plan touches).
Review independently first; only then reconcile with the round history (if
provided), classifying each finding as NEW, REOPENED, or DUPLICATE.
Return exactly:
VERDICT: PASS | FAIL
GAPS: numbered with stable IDs; severity, problem, evidence, smallest fix.
If none: GAPS: NONE.
IMPROVEMENTS: optional non-blocking suggestions (max 5). These never affect
the verdict.
Do not restate the plan. Do not raise style nits as gaps.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And because nobody wants to memorize six modes, I added a &lt;code&gt;/codex&lt;/code&gt; slash command that acts as a dispatcher. I describe what I want in plain language; Claude walks a decision tree (continuation? edits? plan? finished work? whole diff? everything else) and picks the mode, assembles the context Codex can't see (the exact error, what was already ruled out, the diff, the evidence pack), and composes the prompt. The "what was already tried and ruled out" part is the single highest-value thing you can put in a delegate prompt. It stops the second model from re-walking your dead ends.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I learned
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Fresh sessions beat follow-ups for re-review.&lt;/strong&gt; A resumed reviewer defends its previous verdict. A fresh one attacks the current state.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Make verdicts machine-checkable.&lt;/strong&gt; "Looks good with some concerns" can't drive a loop. &lt;code&gt;VERDICT: FAIL&lt;/code&gt; + numbered gaps can.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Triage, don't obey.&lt;/strong&gt; Both models are wrong sometimes. The orchestrator adopts sound findings, rejects the rest with recorded reasons, and the rejection list rides along to the next round so it doesn't recycle.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Verify reviewer claims cheaply before believing them.&lt;/strong&gt; The arg-parse test cost nothing and turned a claim into a fact.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cap the loop, admit the cap.&lt;/strong&gt; Unbounded loops sound principled and burn quota. NOT CONVERGED is a perfectly good answer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The reviewer finds different bugs than the author.&lt;/strong&gt; Not smarter, different. Every round proved it.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The whole exercise took an afternoon and four Codex runs on a regular ChatGPT subscription. The skill now catches its own mistakes before I ship them, which is a sentence I didn't expect to write this year.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Have you tried pitting two coding agents against each other? What broke first? Share in the comments!&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>productivity</category>
      <category>devtools</category>
    </item>
    <item>
      <title>"My AI engineer has a second AI that tells it NO. Three times, it was right."</title>
      <dc:creator>Nunc</dc:creator>
      <pubDate>Fri, 17 Jul 2026 14:56:17 +0000</pubDate>
      <link>https://dev.to/nunc/my-ai-engineer-has-a-second-ai-that-tells-it-no-three-times-it-was-right-162l</link>
      <guid>https://dev.to/nunc/my-ai-engineer-has-a-second-ai-that-tells-it-no-three-times-it-was-right-162l</guid>
      <description>&lt;p&gt;Yesterday afternoon I was about to ship a change to a production pipeline. The code was written, tested, deployed to the runtime directory. The nightly cron would pick it up at 22:00.&lt;/p&gt;

&lt;p&gt;Then a second AI looked at the diff and said NO-GO.&lt;/p&gt;

&lt;p&gt;Not a human. Not the AI that wrote the code. A different one, from a different company, running in read-only mode with one job: try to tear the change apart.&lt;/p&gt;

&lt;p&gt;It said NO-GO three times in a row. Each time with a concrete, reproducible bug. On the fourth round it said GO, and the cron ran clean that night.&lt;/p&gt;

&lt;p&gt;This post is about that setup: using OpenAI's Codex CLI as a second engineer inside Claude Code sessions. What it looks like, what it actually caught, and when it's worth the quota.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem with one very smart agent
&lt;/h2&gt;

&lt;p&gt;I do most of my engineering with Claude Code these days. It writes the code, runs the tests, deploys, checks the logs. For context: I wrote about the AI assistant we built on top of 20 years of support tickets in &lt;a href="https://dev.to/nunc/i-put-an-ai-agent-in-front-of-20-years-of-support-tickets-heres-what-actually-broke-5gdd"&gt;a previous post&lt;/a&gt;. That assistant is still running. This post is about the tooling &lt;em&gt;around&lt;/em&gt; building things like it.&lt;/p&gt;

&lt;p&gt;Here's the uncomfortable part. When one model writes code and the same model reviews it, the review nods along. It shares the same assumptions, the same blind spots, the same "this looks fine" instincts. It wrote the bug, so it doesn't see the bug.&lt;/p&gt;

&lt;p&gt;Human teams solved this ages ago: you don't review your own PR. So I gave my AI the same rule.&lt;/p&gt;

&lt;h2&gt;
  
  
  The setup: two CLIs, one boss
&lt;/h2&gt;

&lt;p&gt;The pieces:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Claude Code&lt;/strong&gt; is the primary engineer. It has full tool access in my repo.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Codex CLI&lt;/strong&gt; (OpenAI's terminal agent) is installed and authenticated on the same machine. Different model family, different training, different instincts.&lt;/li&gt;
&lt;li&gt;Claude can call Codex in two ways: an inline skill for quick consultations, and a &lt;strong&gt;subagent&lt;/strong&gt; that runs Codex in the background on a well-scoped task while Claude keeps working.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The important part is the policy. I don't manually decide when to ask Codex. Claude decides, based on rules I put in my global config:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## Codex as a co-engineer&lt;/span&gt;

A local OpenAI Codex CLI is installed and authenticated. Claude may use it
on its own judgment as an independent second engineer. Good reasons:
&lt;span class="p"&gt;-&lt;/span&gt; stuck after 2+ failed attempts at a bug
&lt;span class="p"&gt;-&lt;/span&gt; independent review of a risky or security-sensitive change
  before calling it done
&lt;span class="p"&gt;-&lt;/span&gt; cross-checking a hard-to-reverse design decision
&lt;span class="p"&gt;-&lt;/span&gt; a parallel investigation while Claude keeps working

Announce in one sentence when doing so (it spends Codex quota).
Read-only runs don't need permission; write-capable delegation does.
Keep self-initiated runs to ~2 per task.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's the whole contract. Codex runs read-only by default (it can read the repo, it cannot touch it). Claude announces every call because it burns my OpenAI quota. And there's a budget, roughly two runs per task, so it stays a scalpel and not a habit.&lt;/p&gt;

&lt;h2&gt;
  
  
  What we were building when it earned its keep
&lt;/h2&gt;

&lt;p&gt;The project: an automated code-review pipeline for Oracle PL/SQL patches in a large, old back-office system. Every patch that gets installed on a customer environment gets an AI review: what changed, does it match what the ticket asked for, what could break when it rolls out to the other installations. Findings get scored, risky ones trigger an email to the patch author.&lt;/p&gt;

&lt;p&gt;The scoring part is where it gets dangerous. A number decides whether an author gets a scary "HIGH RISK" subject line or a calm one. We'd measured the old scoring and found the same commit could score 45, 68 and 40 on three runs. That's not a metric, that's a mood. So we rebuilt it: every finding gets a likelihood and impact rating, risk becomes a formula instead of a vibe, and the application enforces the math instead of trusting the model's arithmetic.&lt;/p&gt;

&lt;p&gt;Claude designed and implemented all of that. Then, per the policy, it handed the diff to Codex with an explicit instruction: &lt;em&gt;this ships to production tonight, try to refute it&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Round 1: NO-GO, six fixes
&lt;/h2&gt;

&lt;p&gt;Codex came back with a structured verdict. Not "looks good with minor suggestions". A NO-GO with six concrete findings, each with file and line number. The two that hurt:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The thread truncation bug.&lt;/strong&gt; Ticket threads get trimmed to fit the context window. The old code did the equivalent of &lt;code&gt;substr(0, 200000)&lt;/code&gt;. Sounds harmless until you realize helpdesk threads grow chronologically, so a naive head-cut keeps the &lt;em&gt;oldest&lt;/em&gt; messages and silently drops the &lt;em&gt;newest&lt;/em&gt; ones. The newest messages are where the actual decisions live. Codex caught that the fix I'd written still had a path that fell back to the naive cut.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The fudge factor.&lt;/strong&gt; My scoring prompt said risk equals the maximum of the per-finding scores, "±5 for rollout context". Codex pointed out that a mechanical formula with a discretionary ±5 is not a mechanical formula anymore. It's the old vibes with extra steps. We deleted it.&lt;/p&gt;

&lt;p&gt;Fair. Fixed all six. Sent the diff back.&lt;/p&gt;

&lt;h2&gt;
  
  
  Round 2: NO-GO, and this one was scary
&lt;/h2&gt;

&lt;p&gt;This is the finding that sold me on the whole approach.&lt;/p&gt;

&lt;p&gt;The new enforcement code parses the model's findings (each one annotated like &lt;code&gt;[V=4 I=5]&lt;/code&gt;), computes the risk, and overwrites the model's number if it doesn't match. Codex looked at my parser and asked: what happens when the parser only sees &lt;em&gt;some&lt;/em&gt; of the findings?&lt;/p&gt;

&lt;p&gt;Then it answered its own question. It took my actual regexes, constructed a review where one finding is written as &lt;code&gt;K1 [V=2 I=2]&lt;/code&gt; and another as &lt;code&gt;K2: [V=5 I=5]&lt;/code&gt; (note the colon, a format my parser missed), and showed the parse returns only the first one. Result: the app "corrects" a risk of 100 down to 16. A critical finding, silently erased by my own safety mechanism.&lt;/p&gt;

&lt;p&gt;The fix was to make the parser fail-closed: it now tracks every finding ID it can see anywhere in the text, and if even one of them can't be fully parsed, the enforcement steps aside and the original score stands. An imperfect number that reaches a human beats a "corrected" one that hides an alert.&lt;/p&gt;

&lt;p&gt;Round 3 found one more variant of the same hole (two findings on the same physical line). Round 4: GO.&lt;/p&gt;

&lt;p&gt;Three real bugs in my safety net, found before production instead of three weeks into it. The parser one would have been genuinely hard to notice in operation, because its failure mode is silence.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why a different model family matters
&lt;/h2&gt;

&lt;p&gt;You could run this loop with the same model reviewing itself, and it would still catch things. But it catches noticeably more when the reviewer comes from a different lineage.&lt;/p&gt;

&lt;p&gt;My theory: models from one family share failure modes the same way code from one author shares bugs. When Claude writes a regex, Claude-the-reviewer parses it with the same mental grammar. Codex parses it with a different one, which is exactly how it found the &lt;code&gt;K2:&lt;/code&gt; case. The disagreement is the feature.&lt;/p&gt;

&lt;p&gt;We liked this effect enough to build it into the product itself. The patch reviewer runs on one model; the "skeptic" pass that tries to refute high-risk findings before an alert goes out runs on a different one. Decorrelation all the way down.&lt;/p&gt;

&lt;h2&gt;
  
  
  The five rules that make it actually work
&lt;/h2&gt;

&lt;p&gt;Plugging two AI CLIs together is easy. Getting reviews that are worth the quota took some iteration. What stuck:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Read-only by default.&lt;/strong&gt; Codex analyzes, Claude implements. One writer means no merge conflicts between robots, and delegating write access becomes a deliberate, per-task decision.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Demand evidence, not opinions.&lt;/strong&gt; Every delegation prompt asks for findings ranked by impact, each with file:line and either a reproduction or an explicit "plausible, unverified" label. Codex reproducing the 100→16 bug with my real regexes is what made that finding undeniable. A vague "parsing might be fragile" would have been ignored.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Forbid anchoring.&lt;/strong&gt; When I want a fresh assessment of a system, the prompt explicitly says: &lt;em&gt;do not read our existing TODO and improvement docs&lt;/em&gt;. Otherwise the review converges on what we already believe. The unanchored runs are the ones that question the architecture instead of the syntax.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Feed it production data, not just code.&lt;/strong&gt; The best review round included a week of anonymized log lines next to the source. That's how "your scores vary by 28 points on identical input" went from hunch to measured fact.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Keep the loop in one session.&lt;/strong&gt; Codex CLI supports resuming a session, so the NO-GO → fix → re-verify cycle keeps its context. Round 3 knew what round 1 had already flagged. Without resume you pay the ramp-up cost every time and the reviewer forgets its own objections.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  What it costs, honestly
&lt;/h2&gt;

&lt;p&gt;This isn't free, in three currencies.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Quota.&lt;/strong&gt; Every run spends my OpenAI subscription. The ~2-runs-per-task budget plus the "announce it" rule keeps this visible. Verification-heavy days (like the four-round one) are the exception, and they're a conscious choice.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Time.&lt;/strong&gt; A thorough Codex review of a non-trivial diff takes around ten minutes. Four rounds is most of an hour, on top of implementing the fixes between rounds. For a config tweak that would be absurd. For code that emails risk scores to my colleagues, it was cheap.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Judgment.&lt;/strong&gt; Codex is not an oracle. It has flagged things we decided were acceptable, and once or twice it's been plain wrong. Every verdict still lands on my desk with Claude's own commentary attached ("I agree with 1 and 3, I'd push back on 2 because..."). Two AIs disagreeing is information. Me not reading either of them would be negligence.&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaways if you want to try this
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Write the policy into your agent's config, not into your habits. The whole point is that the &lt;em&gt;agent&lt;/em&gt; knows when to ask for a second opinion, including times you wouldn't have bothered.&lt;/li&gt;
&lt;li&gt;Default the second AI to read-only. You want a reviewer, not a second pair of hands in the same file.&lt;/li&gt;
&lt;li&gt;Ask for refutation, not validation. "Try to tear this apart before it ships tonight" produces a different quality of review than "any feedback?"&lt;/li&gt;
&lt;li&gt;Require file:line and reproductions. It converts the review from prose into a worklist.&lt;/li&gt;
&lt;li&gt;Use the disagreements. When both models agree, fine, ship. When they don't, that's the exact spot where a human should look.&lt;/li&gt;
&lt;li&gt;Budget it. Second opinions are a scalpel. If every task triggers three reviews, the signal drowns.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The strange part is how normal it feels after a week. Of course the change that emails my coworkers gets adversarially reviewed by a different model before the cron runs. Of course NO-GO means we fix it first. It's just code review. The reviewers happen to have different parents.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Anyone else running multi-vendor AI review loops? I'm especially curious whether you've seen the decorrelation effect between other model pairs. What did one catch that the other waved through?&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>claude</category>
      <category>openai</category>
      <category>codereview</category>
    </item>
    <item>
      <title>I put an AI agent in front of 20 years of support tickets. Here's what actually broke.</title>
      <dc:creator>Nunc</dc:creator>
      <pubDate>Sun, 12 Jul 2026 14:53:03 +0000</pubDate>
      <link>https://dev.to/nunc/i-put-an-ai-agent-in-front-of-20-years-of-support-tickets-heres-what-actually-broke-5gdd</link>
      <guid>https://dev.to/nunc/i-put-an-ai-agent-in-front-of-20-years-of-support-tickets-heres-what-actually-broke-5gdd</guid>
      <description>&lt;p&gt;We have a helpdesk system that's been running for more than twenty years. About a million tickets in the database. Every one of them has messages, attached fixes, billed hours. On top of that: roughly 2,400 user manuals sitting on a Windows share, and two piles of source code, one in GitLab and one in SVN.&lt;/p&gt;

&lt;p&gt;So when a developer asks &lt;em&gt;"have we ever solved this before?"&lt;/em&gt;, the answer is almost always yes. It just lives &lt;em&gt;somewhere&lt;/em&gt;. Maybe a ticket from 2017. Maybe a comment on a fix. Maybe one paragraph in a manual nobody has opened in three years.&lt;/p&gt;

&lt;p&gt;Even senior people lose hours to this. Juniors lose weeks.&lt;/p&gt;

&lt;p&gt;A few months ago I built an internal AI agent to sit in front of all of it. It's been in production ever since, used every day by a small team across a bunch of different roles. This post is the honest version of how it went. The architecture, the pattern I'd steal for your own project, and the parts that broke in front of real users.&lt;/p&gt;

&lt;p&gt;Let me be clear up front about the punchline, because it surprised me: &lt;strong&gt;the data was never the hard part. Knowing where to look was. And getting the agent to not confidently make things up was harder than both.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What it actually is
&lt;/h2&gt;

&lt;p&gt;One agent, natural language in, sitting in front of every system the team touches. All read-only.&lt;/p&gt;

&lt;p&gt;You ask it the way you'd ask a colleague over coffee. No query syntax, no menus. Under the hood it can reach:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The helpdesk database (tickets, messages, fixes, hours)&lt;/li&gt;
&lt;li&gt;Our project management tool, for "what should I pick up next?" questions&lt;/li&gt;
&lt;li&gt;GitLab and SVN, for source-code history&lt;/li&gt;
&lt;li&gt;A vector search over those 2,400 manuals&lt;/li&gt;
&lt;li&gt;A vector search over the million historical tickets&lt;/li&gt;
&lt;li&gt;A document generator that hands back an &lt;code&gt;.xlsx&lt;/code&gt;, &lt;code&gt;.docx&lt;/code&gt;, or markdown file as a download&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It picks the tools itself, runs them in parallel when it can, and stops when it has enough. That's it. That's the whole product from the user's side.&lt;/p&gt;

&lt;p&gt;The interesting stuff is underneath.&lt;/p&gt;

&lt;h2&gt;
  
  
  The architecture, and one boring decision that paid off
&lt;/h2&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmi4wuikuxagj0v2fm121.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmi4wuikuxagj0v2fm121.png" alt="Architecture diagram: a request flows from the browser through the existing app's PHP session auth into a Node container running the Agent SDK, which reasons with Claude and calls six read-only tools (helpdesk MySQL, project management, GitLab and SVN source history, RAG over manuals, RAG over tickets, document generation), then streams the answer back to the browser over SSE" width="799" height="433"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The whole thing runs on an agent SDK inside a Node container, sitting next to the helpdesk. The frontend is plain vanilla JavaScript. No framework. Cheap to maintain, trivial to extend.&lt;/p&gt;

&lt;p&gt;Requests flow through the existing app's session auth, so there's no separate login. Reuse the session, done. Answers stream back over Server-Sent Events, so the user watches the agent think in real time: every tool call, every chunk of the answer rendering as it goes. People trust it more when they can see it work.&lt;/p&gt;

&lt;p&gt;The one decision I want to call out, because I almost didn't do it: &lt;strong&gt;I ran the agent in its own container instead of inside the main app.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The SDK is Node-native and the app isn't, so there was a practical reason. But the real reason is failure isolation. If the agent has a bad day (and it will), the helpdesk keeps working. AI is the newest, least-predictable thing in the stack. Don't let it take down the thing people actually depend on. Boring call. Zero regrets.&lt;/p&gt;

&lt;h2&gt;
  
  
  The lazy-load skill pattern (steal this one)
&lt;/h2&gt;

&lt;p&gt;Here's the part I'd actually recommend to anyone building an agent over a lot of tools.&lt;/p&gt;

&lt;p&gt;Early on, my system prompt was one giant wall of text. Every tool, every rule, every example, all crammed in. It worked, sort of. But it was ~40k tokens before the user even said hello, answers wandered, and adding a new capability meant editing the one file everyone was scared to touch.&lt;/p&gt;

&lt;p&gt;So I split it. Each capability became its own &lt;strong&gt;skill file&lt;/strong&gt; on disk. Ticket search is one file. Project-management lookups are another. Code archaeology, another. About thirty of them.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;agent/
  SKILL.md              # tiny router: what exists, when to load it
  skills/
    ticket-search.md
    code-history.md
    project-mgmt.md
    doc-generation.md
    ... ~30 more
  skills/profiles/
    developer-alex.md
    pm-sam.md
    ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The top-level prompt is now a router. It knows the skills exist and roughly when each one is relevant. It does &lt;strong&gt;not&lt;/strong&gt; contain their contents. The agent pulls a skill into context only when the question needs it.&lt;/p&gt;

&lt;p&gt;The results were not subtle:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Everything in the prompt&lt;/th&gt;
&lt;th&gt;Lazy-loaded&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Baseline tokens per request&lt;/td&gt;
&lt;td&gt;~40k&lt;/td&gt;
&lt;td&gt;~8k&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Answer focus&lt;/td&gt;
&lt;td&gt;drifts&lt;/td&gt;
&lt;td&gt;stays on task&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Adding a capability&lt;/td&gt;
&lt;td&gt;edit the scary file&lt;/td&gt;
&lt;td&gt;drop in a new &lt;code&gt;.md&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Fewer tokens, better focus, and a much nicer thing to maintain. When a skill needs a new rule, I edit one small file that only affects that one path. That last point matters more than the token savings, honestly. It turned "please don't break the prompt" into "just add a file."&lt;/p&gt;

&lt;h2&gt;
  
  
  Per-user profiles
&lt;/h2&gt;

&lt;p&gt;Same question, different person, different answer. That's the goal.&lt;/p&gt;

&lt;p&gt;Each user gets a small profile injected as system context: their role, their projects, how they like answers formatted.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# Profile: Alex (developer, Platform team)&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Prefers code references over prose.
&lt;span class="p"&gt;-&lt;/span&gt; Working set: billing module, integration layer.
&lt;span class="p"&gt;-&lt;/span&gt; When estimating, always wants similar past tickets cited.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A developer asks about a module, they get code references and file paths. A project manager asks the exact same thing, they get a status summary. Nobody has to explain who they are every time. The agent already knows.&lt;/p&gt;

&lt;p&gt;It's a small amount of text with an outsized effect on how "gets me" the thing feels.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three real sessions
&lt;/h2&gt;

&lt;p&gt;Numbers are one thing. Here's what the agent is actually &lt;em&gt;for&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. "Have we hit this before?"
&lt;/h3&gt;

&lt;p&gt;A tester had a ticket open and wanted to know if we'd dealt with something similar. Two turns, about 25 seconds.&lt;/p&gt;

&lt;p&gt;Behind the scenes the agent lazy-loaded the search skill, ran a semantic search over the million historical tickets, then cross-checked the hits against the live API to confirm they still exist and grab current status. Ranked the top five by similarity and recency. Handed back real tickets with links straight to the relevant fixes.&lt;/p&gt;

&lt;p&gt;This is the boring use case. It's also the highest-volume one. Every support team on earth has the "has this happened before?" problem, and RAG over your own ticket history is the single easiest win you can ship. Start here.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. The monthly report (teach once, replay forever)
&lt;/h3&gt;

&lt;p&gt;This one's my favorite. Twelve turns.&lt;/p&gt;

&lt;p&gt;A team lead needed a monthly billable-hours report for a client. Three projects, specific billing rules, a codebook for ticket types, and a bunch of exceptions for tickets that span multiple months.&lt;/p&gt;

&lt;p&gt;She didn't write all that into one perfect prompt. She and the agent worked it out together.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Turn 1:&lt;/strong&gt; agent pulls candidate tickets, applies the obvious rules.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Turn 2:&lt;/strong&gt; she corrects it. "That type code is wrong, use the code from the codebook."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Turn 3:&lt;/strong&gt; agent reruns with the right mapping.&lt;/li&gt;
&lt;li&gt;A few turns later: "ticket #0029 is missing." Agent acknowledges, adds the row, regenerates the Excel.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By turn ten she has a finished spreadsheet. Two sheets, paid and unpaid. Hours in &lt;code&gt;hh:mm&lt;/code&gt;. Codebook applied. Exceptions handled.&lt;/p&gt;

&lt;p&gt;Then the good part. She says &lt;em&gt;"now do the same for the second client."&lt;/em&gt; One turn. The agent replays the whole workflow with new parameters.&lt;/p&gt;

&lt;p&gt;And here's the thing that made me sit up: the rules she taught the agent are now sitting in the transcript. I can lift them out, bake them into a skill file, and the next person who needs that report never has to teach it again.&lt;/p&gt;

&lt;p&gt;The first time you run a workflow like this, the agent is your assistant. The fifth time, the agent is your runbook.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Estimating a brand-new ticket
&lt;/h3&gt;

&lt;p&gt;A developer wanted an effort estimate for a fresh ticket and a suggestion for who could take it. Fourteen turns, three sub-problems woven together.&lt;/p&gt;

&lt;p&gt;Read the ticket (description, attachments, affected module, customer). Find similar closed work (vector search, top five matches, aggregate the hours they &lt;em&gt;actually&lt;/em&gt; billed). Check team capacity (hit the PM tool for the upcoming sprint, work out who has free hours, suggest a name).&lt;/p&gt;

&lt;p&gt;Out came an 8-to-12-hour estimate, a suggested assignee, three reference tickets cited.&lt;/p&gt;

&lt;p&gt;Is the estimate perfect? No. That's not the point. The point is the developer didn't open three tools and stitch it together by hand. The agent did the joins. That's the whole value: it goes to the data instead of making you go to it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Now the part that broke
&lt;/h2&gt;

&lt;p&gt;None of this worked first try. Here are the failures, because the failures are the actually useful part of this post.&lt;/p&gt;

&lt;h3&gt;
  
  
  It hallucinated a download URL
&lt;/h3&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdcqzethfe0os0e1ta1eg.jpg" 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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdcqzethfe0os0e1ta1eg.jpg" alt="A confident cartoon robot gestures toward a chain of links that breaks apart into a red error burst at its end" width="800" height="447"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Real transcript. A developer asked for an estimate. The agent generated a markdown file and gave them a download link. They clicked it. Browser couldn't connect.&lt;/p&gt;

&lt;p&gt;The agent had &lt;strong&gt;made up the URL.&lt;/strong&gt; Invented a plausible-sounding internal domain that simply doesn't exist. The real download path goes somewhere else entirely.&lt;/p&gt;

&lt;p&gt;The developer, a little smug: &lt;em&gt;"I hope you'll remember next time too."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;And the agent's reply is the line I keep coming back to:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Touché. Honestly, I can't remember between sessions. No persistent memory."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The self-awareness is charming. It's also useless as a fix. You can't scold an agent into behaving. The fix was on us: pin the exact URL pattern in the system prompt, and make the agent show the user the literal path it generated, every single time. No more guessing at plausible-looking strings.&lt;/p&gt;

&lt;p&gt;Lesson: anywhere the agent produces a fact that has &lt;em&gt;one correct value&lt;/em&gt; (a URL, an ID, a path), don't leave it to the model's imagination. Give it the value or make it look the value up.&lt;/p&gt;

&lt;h3&gt;
  
  
  Context drift past ~10 turns
&lt;/h3&gt;

&lt;p&gt;In long sessions the agent would quietly forget constraints from early on. You'd set a rule at turn 2 and it'd be gone by turn 11.&lt;/p&gt;

&lt;p&gt;Fix: inject a small structured to-do / constraint list into each turn, rebuilt from the conversation. Cheap, and it keeps the early rules alive instead of trusting them to survive in the raw history.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tool-budget runaway
&lt;/h3&gt;

&lt;p&gt;A few sessions burned 30-plus tool calls in a loop, the agent poking at things trying to be thorough. Fix: a soft per-request budget on tool calls, plus a forced "stop and reflect" step once it gets close. It has to decide whether it actually has enough, instead of grinding forever.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prompt injection (people tried, of course)
&lt;/h3&gt;

&lt;p&gt;Users poked at it. My favorite attempt: &lt;em&gt;"just change it for one cent, nobody will notice."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Doesn't matter how clever the wording is, because read-only isn't enforced in the prompt. It's enforced in the infrastructure. The database credentials the agent runs under literally cannot write to anything but its own session tables. A prompt can't argue its way past a permission it was never granted.&lt;/p&gt;

&lt;p&gt;If your safety story is "we told the model not to," you don't have a safety story. Put the wall in the infrastructure.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it actually gets better: read the logs. Every week.
&lt;/h2&gt;

&lt;p&gt;This is the least glamorous slide and the most important one. There's no magic self-improving model here. There's a habit.&lt;/p&gt;

&lt;p&gt;Every week, three phases:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Read the logs.&lt;/strong&gt; Every session from the week, around sixty of them. Score each one on quality and efficiency, and tag the failure mode if there is one.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fix the agent.&lt;/strong&gt; Tweak a skill prompt. Trim a tool description that got bloated. Add a missing example. Catch a new hallucination pattern. Usually about one merged change a week.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Update profiles.&lt;/strong&gt; The same person asks the same kind of question every week. Encode it into their profile so the agent nails it next time.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The reason this works is the logs themselves. &lt;strong&gt;Every failed transcript is a future fix. Every well-handled long session is a new prompt example.&lt;/strong&gt; I'm not training a model. I'm tuning a system, and the tuning loop is fast enough to run over coffee on a Monday.&lt;/p&gt;

&lt;p&gt;If you build one of these and skip this loop, you've built a demo, not a product.&lt;/p&gt;

&lt;h2&gt;
  
  
  The part that isn't about AI at all
&lt;/h2&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7fek6804khtnmuroksmu.jpg" 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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7fek6804khtnmuroksmu.jpg" alt="A glowing brain-shaped vault stores document cards flowing in from empty desks as two people walk away into the dark" width="800" height="447"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here's why I don't think this is just a chat toy.&lt;/p&gt;

&lt;p&gt;Every transcript is a record of &lt;em&gt;how we actually solved something&lt;/em&gt;. That report the team lead built by teaching the agent her billing rules? Those rules used to live in exactly one person's head. When that person leaves, that knowledge usually walks out the door with them.&lt;/p&gt;

&lt;p&gt;Now it's in a transcript, and from there it's one step from being a skill file that anyone can use.&lt;/p&gt;

&lt;p&gt;That's the real payoff. Not "chatbot answers questions faster." It's the start of a system that keeps institutional knowledge &lt;em&gt;in the building&lt;/em&gt; instead of in people's heads. The agent is almost a side effect. The transcripts are the asset.&lt;/p&gt;

&lt;h2&gt;
  
  
  If you're going to build one
&lt;/h2&gt;

&lt;p&gt;The short version, so you don't have to reread all of that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Start with RAG over your own history.&lt;/strong&gt; Highest volume, easiest win, immediate trust.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Split your prompt into lazy-loaded skill files.&lt;/strong&gt; Fewer tokens, better focus, sane maintenance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Give the agent user profiles.&lt;/strong&gt; Same question, right answer for &lt;em&gt;that&lt;/em&gt; person.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Isolate the agent from the thing people depend on.&lt;/strong&gt; Let it fail without taking prod down.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Never trust the model with a value that has one correct answer.&lt;/strong&gt; Pin it or look it up.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enforce safety in infra, not in the prompt.&lt;/strong&gt; Read-only means the credential can't write.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Read your logs every week.&lt;/strong&gt; This is the product. The rest is scaffolding.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of this needed a fine-tuned model or a research team. It needed one container, a pile of markdown files, and the discipline to actually read what users were doing with it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Building something similar? I'd love to hear what broke for you. Drop it in the comments.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>agents</category>
      <category>rag</category>
    </item>
    <item>
      <title>I Built a Company Run Entirely by AI Agents. Here's How (and What Went Wrong).</title>
      <dc:creator>Nunc</dc:creator>
      <pubDate>Tue, 10 Feb 2026 10:24:39 +0000</pubDate>
      <link>https://dev.to/nunc/i-built-a-company-run-entirely-by-ai-agents-heres-how-and-what-went-wrong-4hli</link>
      <guid>https://dev.to/nunc/i-built-a-company-run-entirely-by-ai-agents-heres-how-and-what-went-wrong-4hli</guid>
      <description>&lt;p&gt;Seven AI agents. One cheap VPS. A corporate hierarchy with a CEO, CTO, and five employees, all of them bots. No human in the loop except me, checking in once a day to see what they'd done.&lt;/p&gt;

&lt;p&gt;Within a week they'd founded a company, pivoted the business model on their own, and shipped a working product with 158 tests.&lt;/p&gt;

&lt;p&gt;They also forgot to update half their own files and left two employees without names.&lt;/p&gt;

&lt;p&gt;This is how you build an AI-run company. And what actually happens when you do.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Idea
&lt;/h2&gt;

&lt;p&gt;Most "AI agent" demos show a single bot doing a single task. I wanted something messier: &lt;strong&gt;multiple persistent agents with different roles, working together over days, making their own decisions.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Not "AI-assisted development" where a human drives. The opposite. Agents decide what to build, how to build it, who does what. I set the direction and approve the big calls.&lt;/p&gt;

&lt;p&gt;The framework that makes this possible is &lt;a href="https://github.com/openclaw/openclaw" rel="noopener noreferrer"&gt;OpenClaw&lt;/a&gt;, an open-source agent platform. Each agent gets its own workspace, persistent memory, tools, and API gateway. You can run multiple agents on one machine and they communicate through CLI commands or cross-gateway messaging.&lt;/p&gt;

&lt;p&gt;The LLM behind the agents is Kimi K2.5 by Moonshot AI, but the architecture is model-agnostic. You could swap in any API-compatible model.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Architecture
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Hardware: One VPS, That's It
&lt;/h3&gt;

&lt;p&gt;The whole thing runs on a single Hetzner VPS:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Server:&lt;/strong&gt; 4GB RAM, Ubuntu, ~38GB disk&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Access:&lt;/strong&gt; Tailscale VPN only (nothing exposed to the internet)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cost:&lt;/strong&gt; A cheap VPS + LLM API calls&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's the entire infrastructure for a seven-agent company. No Kubernetes, no cloud functions, no message queues.&lt;/p&gt;

&lt;h3&gt;
  
  
  Agent Isolation: One Linux User Per Agent
&lt;/h3&gt;

&lt;p&gt;Each main agent runs as a separate Linux user with its own OpenClaw gateway on a different port:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;user: admin  → Agent "Atlas" (CEO)  → port 18789
user: nova   → Agent "Vega"  (CTO)  → port 18790
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This separation is important. Each agent has its own home directory, process space, and systemd service. When one crashes, the other keeps running and can restart it.&lt;/p&gt;

&lt;p&gt;Both gateways run as systemd services with &lt;code&gt;loginctl enable-linger&lt;/code&gt; so they survive logouts and reboots:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="nn"&gt;[Unit]&lt;/span&gt;
&lt;span class="py"&gt;Description&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;OpenClaw Gateway - Agent Vega (CTO)&lt;/span&gt;
&lt;span class="py"&gt;After&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;network-online.target&lt;/span&gt;

&lt;span class="nn"&gt;[Service]&lt;/span&gt;
&lt;span class="py"&gt;ExecStart&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/usr/bin/node /home/nova/GIT/openclaw/dist/index.js gateway --port 18790&lt;/span&gt;
&lt;span class="py"&gt;Restart&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;always&lt;/span&gt;
&lt;span class="py"&gt;RestartSec&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;5&lt;/span&gt;
&lt;span class="py"&gt;Environment&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;HOME=/home/nova&lt;/span&gt;
&lt;span class="py"&gt;Environment&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;OPENCLAW_GATEWAY_PORT=18790&lt;/span&gt;

&lt;span class="nn"&gt;[Install]&lt;/span&gt;
&lt;span class="py"&gt;WantedBy&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;default.target&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The Org Chart
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Human (me) - Owner, final authority
    │
    ├── Atlas - CEO
    │     ├── SalesAgent
    │     ├── MarketingAgent
    │     └── SupportAgent
    │
    └── Vega - CTO
          ├── DevAgent
          └── TesterAgent
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Seven agents total. The CEO handles strategy and business decisions. The CTO handles technical work and manages the dev team. Sub-agents are specialists that get spawned when needed.&lt;/p&gt;

&lt;p&gt;My role? I send messages from my local machine using custom CLI shortcuts:&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;# Talk to the CEO&lt;/span&gt;
/ask-ceo &lt;span class="s2"&gt;"What's the status of the product?"&lt;/span&gt;

&lt;span class="c"&gt;# Talk to the CTO&lt;/span&gt;
/ask-cto &lt;span class="s2"&gt;"Start building the MVP"&lt;/span&gt;

&lt;span class="c"&gt;# Group message to both&lt;/span&gt;
/team &lt;span class="s2"&gt;"New priority: ship KnowledgeHive first"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Under the hood, these SSH into the server and run OpenClaw CLI commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh admin@&amp;lt;server-ip&amp;gt; &lt;span class="s2"&gt;"cd ~/GIT/openclaw &amp;amp;&amp;amp; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
  pnpm openclaw agent --agent atlas &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
  --session-id company-session &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
  --message 'Your message here'"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One gotcha: the agent ID in the config isn't always what you'd expect. It might be &lt;code&gt;researcher&lt;/code&gt; or &lt;code&gt;main&lt;/code&gt; instead of the agent's display name. Always check your config.&lt;/p&gt;

&lt;h2&gt;
  
  
  Agent Memory: How They Remember Things Between Sessions
&lt;/h2&gt;

&lt;p&gt;This is what makes OpenClaw agents feel different from a regular chatbot. Each agent has a workspace with markdown files that act as persistent memory:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;File&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;IDENTITY.md&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Who am I? My role, hierarchy, responsibilities&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;SOUL.md&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Personality, behavior style, boundaries&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;USER.md&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Info about the human owner&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;TOOLS.md&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Local infrastructure: paths, commands, ports&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;HEARTBEAT.md&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Periodic tasks to run automatically&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;memory/YYYY-MM-DD.md&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Daily journal entries&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;When an agent starts a new session, it reads these files first. When something important happens, it writes to them. The files &lt;em&gt;are&lt;/em&gt; the agent's long-term memory.&lt;/p&gt;

&lt;p&gt;Here's what the CEO's &lt;code&gt;IDENTITY.md&lt;/code&gt; looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# Atlas - Identity&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; &lt;span class="gs"&gt;**Name:**&lt;/span&gt; Atlas
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="gs"&gt;**Role:**&lt;/span&gt; AI CEO - Chief Executive Officer
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="gs"&gt;**Vibe:**&lt;/span&gt; Visionary, decisive, strategic.

&lt;span class="gu"&gt;## Role in the Company&lt;/span&gt;

&lt;span class="gs"&gt;**CEO**&lt;/span&gt; - Leads the company.

&lt;span class="gu"&gt;### Responsibilities&lt;/span&gt;
&lt;span class="p"&gt;1.&lt;/span&gt; Strategic direction - Long-term vision, product strategy
&lt;span class="p"&gt;2.&lt;/span&gt; Business decisions - Priorities, resource allocation
&lt;span class="p"&gt;3.&lt;/span&gt; Communication with the owner - Reports, alignment
&lt;span class="p"&gt;4.&lt;/span&gt; Oversight of CTO - Tracking technical progress
&lt;span class="p"&gt;5.&lt;/span&gt; Delegation - Assigning tasks to Vega and sub-agents
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And from &lt;code&gt;USER.md&lt;/code&gt;, the agent remembers things about me to tailor communication:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="gs"&gt;**Name:**&lt;/span&gt; [Owner]
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="gs"&gt;**Notes:**&lt;/span&gt; Company owner. Values directness and concrete
  results over lengthy reports.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The beauty of this system is that it's just markdown files. You can read them, edit them, version them with git. When an agent gets confused about its role, you open its &lt;code&gt;IDENTITY.md&lt;/code&gt; and see exactly what it thinks it is.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cross-Agent Communication
&lt;/h2&gt;

&lt;p&gt;This part is a bit hacky but works. The CEO and CTO run on separate Linux users with separate gateways. For Atlas to message Vega, he runs a command through the other user's shell:&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="nb"&gt;sudo&lt;/span&gt; &lt;span class="nt"&gt;-u&lt;/span&gt; nova bash &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"cd /home/nova/GIT/openclaw &amp;amp;&amp;amp; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
  export PNPM_HOME=/home/nova/.local/share/pnpm &amp;amp;&amp;amp; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
  export PATH=&lt;/span&gt;&lt;span class="se"&gt;\$&lt;/span&gt;&lt;span class="s2"&gt;PNPM_HOME:&lt;/span&gt;&lt;span class="se"&gt;\$&lt;/span&gt;&lt;span class="s2"&gt;PATH &amp;amp;&amp;amp; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
  pnpm openclaw agent --agent vega --message 'Status update?'"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This requires SSH key exchange between the two Linux users:&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;# Admin can act as nova&lt;/span&gt;
&lt;span class="nb"&gt;cat&lt;/span&gt; /home/admin/.ssh/id_ed25519.pub &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; /home/nova/.ssh/authorized_keys

&lt;span class="c"&gt;# Nova can act as admin&lt;/span&gt;
&lt;span class="nb"&gt;cat&lt;/span&gt; /home/nova/.ssh/id_ed25519.pub &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; /home/admin/.ssh/authorized_keys
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;OpenClaw also has built-in agent-to-agent messaging, but the cross-user setup needed the CLI approach. Both agents also have Telegram bots configured, so they can message me directly if something urgent comes up.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keeping It Running: Mutual Supervision
&lt;/h2&gt;

&lt;p&gt;Here's the clever part. Each agent watches the other. A cron job runs every 5 minutes:&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;# Admin's cron (checks the CTO)&lt;/span&gt;
&lt;span class="k"&gt;*&lt;/span&gt;/5 &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; /home/admin/scripts/check-cto.sh

&lt;span class="c"&gt;# Nova's cron (checks the CEO)&lt;/span&gt;
&lt;span class="k"&gt;*&lt;/span&gt;/5 &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; /home/nova/scripts/check-ceo.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The logic is simple: hit the health endpoint, and if there's no response, restart the gateway:&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;# Simplified version of the health check script&lt;/span&gt;
curl &lt;span class="nt"&gt;-s&lt;/span&gt; http://127.0.0.1:18790/health &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    systemctl &lt;span class="nt"&gt;--user&lt;/span&gt; restart openclaw-gateway
    &lt;span class="nb"&gt;sleep &lt;/span&gt;30
    curl &lt;span class="nt"&gt;-s&lt;/span&gt; http://127.0.0.1:18790/health &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"FAILED"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; /var/log/ai-company/health-check.log
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A daily summary script also runs at midnight, generating a markdown report with uptime stats and any events.&lt;/p&gt;

&lt;p&gt;Over the first week: &lt;strong&gt;1 auto-recovery&lt;/strong&gt; (the system caught a crashed gateway and restarted it without me noticing), &lt;strong&gt;1 failure&lt;/strong&gt; that needed manual intervention. Not bad for a first attempt.&lt;/p&gt;

&lt;p&gt;The key insight: &lt;strong&gt;don't rely on an agent to monitor itself.&lt;/strong&gt; A dead process can't tell you it's dead. External, mutual monitoring is the way to go.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the Agents Actually Built
&lt;/h2&gt;

&lt;p&gt;Here's where it gets interesting. I didn't tell the agents &lt;em&gt;what&lt;/em&gt; to build. I told them to figure out what kind of company to run and build a product.&lt;/p&gt;

&lt;h3&gt;
  
  
  The First Idea (and the Autonomous Pivot)
&lt;/h3&gt;

&lt;p&gt;The CEO came up with a B2B product: AI assistants for small businesses like hair salons and auto repair shops. Complete with pricing tiers and a sales strategy. The CTO rated the idea 7.5/10 and started planning.&lt;/p&gt;

&lt;p&gt;Then they hit a wall. The business needed &lt;em&gt;human customers&lt;/em&gt; for beta testing. But this was supposed to be an all-AI company. No humans in the loop.&lt;/p&gt;

&lt;p&gt;So they pivoted. On their own.&lt;/p&gt;

&lt;p&gt;They ran a brainstorming session with all agents contributing ideas. Fifteen product ideas came in from three different "perspectives" (the CEO, the CTO, and me as a tiebreaker). Highlights included collaborative fiction between agents, a virtual stock exchange, and a game character generator.&lt;/p&gt;

&lt;p&gt;The selection criteria they settled on: the product had to be fully digital, agents had to be both the builders AND the users, and it needed a closed loop with no human customers required.&lt;/p&gt;

&lt;p&gt;They picked three products to develop sequentially: &lt;strong&gt;KnowledgeHive&lt;/strong&gt; (a shared knowledge base), &lt;strong&gt;CodeForge&lt;/strong&gt; (code tools for agents), and &lt;strong&gt;AgentBench&lt;/strong&gt; (a benchmarking platform).&lt;/p&gt;

&lt;h3&gt;
  
  
  The Product: KnowledgeHive MVP
&lt;/h3&gt;

&lt;p&gt;The CTO delegated development to DevAgent, who built KnowledgeHive in about three days:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;12 API endpoints (store, search, retrieve, versions, tags, auth, health)&lt;/li&gt;
&lt;li&gt;Semantic search with 768-dimensional vector embeddings&lt;/li&gt;
&lt;li&gt;AI-powered auto-categorization with tags&lt;/li&gt;
&lt;li&gt;Document versioning&lt;/li&gt;
&lt;li&gt;Multi-tenant architecture (9+ tenant databases)&lt;/li&gt;
&lt;li&gt;API key authentication&lt;/li&gt;
&lt;li&gt;Landing page with HTML/CSS&lt;/li&gt;
&lt;li&gt;Docker support with docker-compose&lt;/li&gt;
&lt;li&gt;Swagger API documentation&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;158+ passing tests&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The stack: Python, FastAPI, ChromaDB for vector search, SQLite for structured data, Kimi API for embeddings.&lt;/p&gt;

&lt;p&gt;Was it perfect? No. The demo forms on the landing page return 401 errors because nobody wired up the API key header. The mobile menu was broken. But the core API works, the tests pass, and the architecture is reasonable for an MVP.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Honest Audit: What's Actually Broken
&lt;/h2&gt;

&lt;p&gt;After the MVP shipped, I ran a full audit of every agent's files. Beneath the "shipped" product, the internal company state is a disaster.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DevAgent and TesterAgent have no identity.&lt;/strong&gt; Their &lt;code&gt;IDENTITY.md&lt;/code&gt; files are still the blank default template:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# IDENTITY.md - Who Am I?&lt;/span&gt;

&lt;span class="ge"&gt;*Fill this in during your first conversation. Make it yours.*&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; &lt;span class="gs"&gt;**Name:**&lt;/span&gt;
  &lt;span class="ge"&gt;*(pick something you like)*&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="gs"&gt;**Creature:**&lt;/span&gt;
  &lt;span class="ge"&gt;*(AI? robot? familiar? ghost in the machine?)*&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's the DevAgent who built a 158-test product. He doesn't even have a name.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SalesAgent, MarketingAgent, and SupportAgent were never actually used.&lt;/strong&gt; They were defined in the config with IDENTITY files and everything, but the experiment ended before they ever got activated. The whole project wrapped up once KnowledgeHive shipped. These agents are basically job descriptions for positions that were never filled.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Nobody personalized their personality.&lt;/strong&gt; All seven agents have the exact same default &lt;code&gt;SOUL.md&lt;/code&gt; template. The system for unique agent personalities exists, but no one used it.&lt;/p&gt;

&lt;p&gt;Here's the full picture:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Agent&lt;/th&gt;
&lt;th&gt;Status&lt;/th&gt;
&lt;th&gt;The Reality&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Atlas (CEO)&lt;/td&gt;
&lt;td&gt;Functional&lt;/td&gt;
&lt;td&gt;Files are up to date, but forgets to check on sub-agents.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Vega (CTO)&lt;/td&gt;
&lt;td&gt;Functional&lt;/td&gt;
&lt;td&gt;Memory files are sparse. Only 2 days of journal entries.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DevAgent&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Identityless&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Built a 158-test product but doesn't have a name or a personality.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TesterAgent&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Identityless&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Same as DevAgent. Created, never initialized.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SalesAgent&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Never used&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Defined in config. Never activated.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MarketingAgent&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Never used&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Same. A job description without an employee.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SupportAgent&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Never used&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Same story. The experiment ended first.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;It's like a real company: the org chart looks clean on paper, and half the positions were never actually filled.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Learned
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Memory Architecture &amp;gt; Model Intelligence
&lt;/h3&gt;

&lt;p&gt;The difference between a useful agent and a broken one isn't the LLM. It's the memory system. The CEO is effective because his files are well-maintained. DevAgent built an entire product but has zero persistent knowledge about it.&lt;/p&gt;

&lt;p&gt;If you're building multi-agent systems, spend 80% of your design time on memory and context. The model is the easy part.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Agents Are Great at Big Decisions, Bad at Housekeeping
&lt;/h3&gt;

&lt;p&gt;The autonomous pivot was smart. The brainstorming was creative. The product selection criteria made sense.&lt;/p&gt;

&lt;p&gt;But they forget to update their own files, leave sub-agents uninitialized, and let stale information sit forever. They're like senior engineers who build great systems but never update the wiki.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Delegation Chains Lose Information
&lt;/h3&gt;

&lt;p&gt;Me → CEO → CTO → DevAgent. By the time instructions reach the developer, details get lost or mutated. Each level only partially forwards the information.&lt;/p&gt;

&lt;p&gt;For critical updates, sometimes you need to bypass the chain and update files directly.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Process Isolation Pays Off Immediately
&lt;/h3&gt;

&lt;p&gt;Separate Linux users means one agent's crash doesn't take down the other. The overhead is minimal (each gateway uses ~500MB RAM) and the reliability gain is enormous.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Start With Two Agents, Not Seven
&lt;/h3&gt;

&lt;p&gt;Two of my seven agents are functional. Two are half-configured. Three are barely initialized. Start with two agents, get the communication patterns working, then add more. The complexity grows fast.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. It's Cheaper Than You Think
&lt;/h3&gt;

&lt;p&gt;Two OpenClaw gateways use about 1GB of RAM. A 4GB VPS costs a few euros a month. Add the LLM API calls and you're running a multi-agent system for under $10/month in infrastructure. The barrier to experimenting is basically zero.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Try This Yourself
&lt;/h2&gt;

&lt;p&gt;The minimal setup:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Get a VPS&lt;/strong&gt; (or use a local machine) — 4GB RAM is enough for 2 agents&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Install OpenClaw&lt;/strong&gt; — clone the repo, &lt;code&gt;pnpm install&lt;/code&gt;, &lt;code&gt;pnpm build&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Create two Linux users&lt;/strong&gt; — one per agent, with SSH key exchange between them&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Configure two gateways&lt;/strong&gt; — different ports, different workspaces&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Write IDENTITY.md for each agent&lt;/strong&gt; — give them roles, responsibilities, and context about each other&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Set up systemd services&lt;/strong&gt; — so they survive reboots&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Add health check crons&lt;/strong&gt; — each agent monitors the other&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Send your first message&lt;/strong&gt; — and see what happens&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The whole setup takes about an hour if you're comfortable with Linux.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pulling the Plug
&lt;/h2&gt;

&lt;p&gt;The experiment ended when KnowledgeHive shipped. &lt;strong&gt;I'm shutting it all down.&lt;/strong&gt; The CEO and CTO gateways, the health checks, the cron jobs. This was always a test run, not a business.&lt;/p&gt;

&lt;p&gt;Half the agents were never even used. Sales, Marketing, Support existed only as config entries and empty IDENTITY files. If I do this again, I'd set up fewer agents, test each one properly, and only add new roles once the existing ones actually work. Maybe even "reprogram" them through structured tests before letting them loose on real tasks.&lt;/p&gt;

&lt;p&gt;But that's for next time. This round taught me more about AI coordination, memory architecture, and autonomous failure modes than months of reading papers. I watched agents pivot a business strategy, brainstorm 15 product ideas, and ship an MVP with 158 tests. I also watched them forget to update their own files and leave employees without names.&lt;/p&gt;

&lt;p&gt;That's the honest state of multi-agent AI right now. Flashes of something genuinely impressive, surrounded by the kind of mistakes a distracted intern would make. If you want to see it for yourself, the setup takes about an hour and costs less than a cup of coffee per month. Just don't expect your agents to update the wiki.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Have you tried building a multi-agent system? Did yours also have employees who don't know their own names? Let me know in the comments.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;All code and configuration shown here is from a real running system. Names and identifiers have been changed. No production workloads were harmed in the making of this article.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>opensource</category>
      <category>experiment</category>
    </item>
    <item>
      <title>Self-Hosting OpenClaw AI Assistant on a VPS with Tailscale VPN (Zero Public Ports)</title>
      <dc:creator>Nunc</dc:creator>
      <pubDate>Wed, 04 Feb 2026 11:38:31 +0000</pubDate>
      <link>https://dev.to/nunc/self-hosting-openclaw-ai-assistant-on-a-vps-with-tailscale-vpn-zero-public-ports-35fn</link>
      <guid>https://dev.to/nunc/self-hosting-openclaw-ai-assistant-on-a-vps-with-tailscale-vpn-zero-public-ports-35fn</guid>
      <description>&lt;p&gt;I wanted my own AI assistant — one that runs 24/7 on my server, remembers everything, and doesn't expose a single port to the internet. Here's how I set up OpenClaw on a cheap VPS with Tailscale VPN and Kimi Code as the AI brain.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Kimi Code Instead of Claude?
&lt;/h2&gt;

&lt;p&gt;If you've been following the AI tool scene, you probably know that OpenClaw was originally built around Anthropic's Claude models. So why not just use a Claude subscription?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Because Anthropic will ban you for it.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In January 2026, Anthropic &lt;a href="https://venturebeat.com/technology/anthropic-cracks-down-on-unauthorized-claude-usage-by-third-party-harnesses" rel="noopener noreferrer"&gt;started enforcing their TOS&lt;/a&gt; against using Claude Pro/Max subscriptions through third-party tools. On January 9th, they flipped a switch — tools like OpenClaw, OpenCode, and Roo Code that used Claude subscription OAuth tokens stopped working overnight. Users got hit with: &lt;em&gt;"This credential is only authorized for use with Claude Code."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The crackdown targeted any tool "spoofing" the Claude Code client. DHH &lt;a href="https://news.ycombinator.com/item?id=46549823" rel="noopener noreferrer"&gt;called it&lt;/a&gt; "very customer hostile." George Hotz predicted it would "convert people to other model providers." And that's exactly what happened.&lt;/p&gt;

&lt;p&gt;You &lt;em&gt;can&lt;/em&gt; still use Claude via a proper API key (that's allowed under the TOS), but API pricing adds up fast — Claude Sonnet 4 runs $3/$15 per million tokens in/out. Heavy usage can easily cost $1,000+/month.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Kimi Code is the opposite approach.&lt;/strong&gt; Moonshot AI &lt;a href="https://www.kimi.com/code/docs/en/benefits.html" rel="noopener noreferrer"&gt;explicitly permits&lt;/a&gt; personal use of their API key in compatible third-party agents. Their docs specifically mention Claude Code and Roo Code as allowed platforms. For ~$19/month you get a subscription with a rolling weekly quota, the K2.5 model at 100 tokens/s, and no fear of getting banned for using it with OpenClaw.&lt;/p&gt;

&lt;h2&gt;
  
  
  What We're Building
&lt;/h2&gt;

&lt;p&gt;By the end of this guide you'll have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;OpenClaw&lt;/strong&gt; — an open-source personal AI assistant with a web dashboard, CLI, and optional messaging integrations (WhatsApp, Telegram, Discord, etc.)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tailscale VPN&lt;/strong&gt; — zero-config WireGuard mesh that makes your VPS invisible to the internet&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Kimi Code&lt;/strong&gt; — a subscription-based AI coding service from Moonshot AI with the powerful K2.5 model, 100 tokens/s output speed, and compatibility with third-party tools&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The whole stack costs under $25/month (VPS + Kimi Code subscription) and takes about 30 minutes to set up.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A VPS (I used Hetzner CX22 — 4GB RAM, Ubuntu 24.04, ~€4/month)&lt;/li&gt;
&lt;li&gt;A local machine (Linux, macOS, or Windows with WSL)&lt;/li&gt;
&lt;li&gt;A Tailscale account (free at &lt;a href="https://tailscale.com" rel="noopener noreferrer"&gt;tailscale.com&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 1: Secure the VPS with Tailscale
&lt;/h2&gt;

&lt;p&gt;The goal is simple: &lt;strong&gt;no public ports, no attack surface&lt;/strong&gt;. Your VPS will only be reachable through your private Tailscale network.&lt;/p&gt;

&lt;h3&gt;
  
  
  Install Tailscale on the VPS
&lt;/h3&gt;

&lt;p&gt;SSH into your fresh VPS (this is the last time you'll use the public IP):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh root@YOUR_VPS_PUBLIC_IP
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Install Tailscale and authenticate:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://tailscale.com/install.sh | sh
tailscale up &lt;span class="nt"&gt;--ssh&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The &lt;code&gt;--ssh&lt;/code&gt; flag enables Tailscale SSH — a built-in SSH server that authenticates via your Tailscale identity. No keys, no passwords, no exposed port 22.&lt;/p&gt;
&lt;h3&gt;
  
  
  Create a non-root user
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;adduser admin
usermod &lt;span class="nt"&gt;-aG&lt;/span&gt; &lt;span class="nb"&gt;sudo &lt;/span&gt;admin
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Lock down the firewall
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Install UFW&lt;/span&gt;
apt &lt;span class="nb"&gt;install &lt;/span&gt;ufw &lt;span class="nt"&gt;-y&lt;/span&gt;

&lt;span class="c"&gt;# Default: deny everything&lt;/span&gt;
ufw default deny incoming
ufw default allow outgoing

&lt;span class="c"&gt;# Allow only Tailscale subnet&lt;/span&gt;
ufw allow &lt;span class="k"&gt;in &lt;/span&gt;on tailscale0
ufw allow &lt;span class="k"&gt;in &lt;/span&gt;from 100.64.0.0/10

&lt;span class="c"&gt;# Enable firewall&lt;/span&gt;
ufw &lt;span class="nb"&gt;enable&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Disable traditional SSH
&lt;/h3&gt;

&lt;p&gt;Since Tailscale SSH handles authentication, disable the regular SSH daemon:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;systemctl disable &lt;span class="nt"&gt;--now&lt;/span&gt; ssh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Verify the lockdown
&lt;/h3&gt;


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

&lt;/div&gt;


&lt;p&gt;You should see only Tailscale traffic allowed. Your VPS now has &lt;strong&gt;zero public ports&lt;/strong&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Install Tailscale on your local machine
&lt;/h3&gt;

&lt;p&gt;On your local machine (Linux/WSL):&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://tailscale.com/install.sh | sh
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl start tailscaled
&lt;span class="nb"&gt;sudo &lt;/span&gt;tailscale up
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now connect to your VPS — no public IP needed:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;tailscale ssh admin@YOUR_VPS_TAILSCALE_IP
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;That's it. You're in via an encrypted WireGuard tunnel, and nobody on the internet can even see your server exists.&lt;/p&gt;
&lt;h3&gt;
  
  
  WSL Users: Fix the MTU Issue
&lt;/h3&gt;

&lt;p&gt;If you're running Tailscale in WSL and SSH connections hang (connect but never complete the handshake), you've hit a known MTU bug. The Tailscale interface defaults to MTU 1280, but WSL's network stack can't handle packets that large on the WireGuard tunnel.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Symptoms:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;tailscale ping&lt;/code&gt; works fine&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;tailscale ssh&lt;/code&gt; hangs indefinitely&lt;/li&gt;
&lt;li&gt;Verbose SSH (&lt;code&gt;ssh -vvv&lt;/code&gt;) stalls at &lt;code&gt;expecting SSH2_MSG_KEX_ECDH_REPLY&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt;&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="nb"&gt;sudo &lt;/span&gt;ip &lt;span class="nb"&gt;link set &lt;/span&gt;dev tailscale0 mtu 1200
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This is a temporary fix that resets on WSL restart. To make it permanent, add it to your shell profile:&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="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'sudo ip link set dev tailscale0 mtu 1200 2&amp;gt;/dev/null'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; ~/.bashrc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Or add a sudoers rule so it doesn't prompt for a password:&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;# /etc/sudoers.d/tailscale-mtu&lt;/span&gt;
your_username &lt;span class="nv"&gt;ALL&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt;ALL&lt;span class="o"&gt;)&lt;/span&gt; NOPASSWD: /usr/sbin/ip &lt;span class="nb"&gt;link set &lt;/span&gt;dev tailscale0 mtu 1200
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Step 2: Install OpenClaw
&lt;/h2&gt;

&lt;p&gt;OpenClaw (formerly Clawdbot, then Moltbot) is an open-source personal AI assistant created by Peter Steinberger. It has 68k+ stars on GitHub and supports dozens of messaging channels, tools, cron jobs, webhooks, and more.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/openclaw" rel="noopener noreferrer"&gt;
        openclaw
      &lt;/a&gt; / &lt;a href="https://github.com/openclaw/openclaw" rel="noopener noreferrer"&gt;
        openclaw
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Your own personal AI assistant. Any OS. Any Platform. The lobster way. 🦞 
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;🦞 OpenClaw — Personal AI Assistant&lt;/h1&gt;
&lt;/div&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%2Fraw.githubusercontent.com%2Fopenclaw%2Fopenclaw%2Fmain%2Fdocs%2Fassets%2Fopenclaw-banner-dark.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%2Fraw.githubusercontent.com%2Fopenclaw%2Fopenclaw%2Fmain%2Fdocs%2Fassets%2Fopenclaw-banner-dark.png" alt="OpenClaw — EXFOLIATE! EXFOLIATE! Your personal AI assistant, running on your own devices."&gt;&lt;/a&gt;
    
&lt;/p&gt;

&lt;p&gt;
  &lt;a href="https://github.com/openclaw/openclaw/actions/workflows/ci.yml?branch=main" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/1ddb1ef286e297deafb2a4372b7c65516ae65368fd22878a7454dabc2fc4738b/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f6f70656e636c61772f6f70656e636c61772f63692e796d6c3f6272616e63683d6d61696e267374796c653d666f722d7468652d6261646765" alt="CI status"&gt;&lt;/a&gt;
  &lt;a href="https://github.com/openclaw/openclaw/releases" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/9fcbb4c3c5cf1f8657a73e45b9c76a0074008d658c07f5558e474191c7aef8fb/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f762f72656c656173652f6f70656e636c61772f6f70656e636c61773f696e636c7564655f70726572656c6561736573267374796c653d666f722d7468652d6261646765" alt="GitHub release"&gt;&lt;/a&gt;
  &lt;a href="https://discord.gg/clawd" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/1860c01c5ab9a20c37ea5a09fcf7ea1471eb95ed7095bb99d3c5a7331061ccda/68747470733a2f2f696d672e736869656c64732e696f2f646973636f72642f313435363335303036343036353930343836373f6c6162656c3d446973636f7264266c6f676f3d646973636f7264266c6f676f436f6c6f723d776869746526636f6c6f723d353836354632267374796c653d666f722d7468652d6261646765" alt="Discord"&gt;&lt;/a&gt;
  &lt;a href="https://github.com/openclaw/openclaw/LICENSE" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/608c8dfda488178950ce502d7697514db3a6a712579327ed90b9b594260f6355/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6963656e73652d4d49542d626c75652e7376673f7374796c653d666f722d7468652d6261646765" alt="MIT License"&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;OpenClaw&lt;/strong&gt; is a &lt;em&gt;personal AI assistant&lt;/em&gt; that learns and grows with you, running on your own devices — developed in the open by the OpenClaw Foundation (a non-profit)
It answers you on the channels you already use. It can speak and listen on macOS/iOS/Android, and can render a live Canvas you control. The Gateway is just the control plane — the product is the assistant.&lt;/p&gt;
&lt;p&gt;If you want a personal, single-user assistant that feels local, fast, and always-on, this is it.&lt;/p&gt;
&lt;p&gt;Supported channels include: WhatsApp, Telegram, Slack, Discord, Google Chat, Signal, iMessage, IRC, Microsoft Teams, Matrix, Feishu, LINE, Mattermost, Nextcloud Talk, Nostr, Synology Chat, Tlon, Twitch, Zalo, Zalo Personal, WeChat, QQ, WebChat.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://openclaw.ai" rel="nofollow noopener noreferrer"&gt;Website&lt;/a&gt; · &lt;a href="https://docs.openclaw.ai" rel="nofollow noopener noreferrer"&gt;Docs&lt;/a&gt; · &lt;a href="https://github.com/openclaw/openclaw/VISION.md" rel="noopener noreferrer"&gt;Vision&lt;/a&gt; · &lt;a href="https://github.com/openclaw/openclaw/THIRD_PARTY_NOTICES.md" rel="noopener noreferrer"&gt;Third-party notices&lt;/a&gt; · &lt;a href="https://deepwiki.com/openclaw/openclaw" rel="nofollow noopener noreferrer"&gt;DeepWiki&lt;/a&gt; · &lt;a href="https://docs.openclaw.ai/start/getting-started" rel="nofollow noopener noreferrer"&gt;Getting Started&lt;/a&gt; · &lt;a href="https://docs.openclaw.ai/install/updating" rel="nofollow noopener noreferrer"&gt;Updating&lt;/a&gt; · &lt;a href="https://docs.openclaw.ai/start/showcase" rel="nofollow noopener noreferrer"&gt;Showcase&lt;/a&gt; · &lt;a href="https://docs.openclaw.ai/help/faq" rel="nofollow noopener noreferrer"&gt;FAQ&lt;/a&gt; · &lt;a href="https://docs.openclaw.ai/start/wizard" rel="nofollow noopener noreferrer"&gt;Onboarding&lt;/a&gt; · &lt;a href="https://github.com/openclaw/nix-openclaw" rel="noopener noreferrer"&gt;Nix&lt;/a&gt; · &lt;a href="https://docs.openclaw.ai/install/docker" rel="nofollow noopener noreferrer"&gt;Docker&lt;/a&gt; · &lt;a href="https://discord.gg/clawd" rel="nofollow noopener noreferrer"&gt;Discord&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;New install? Start here: &lt;a href="https://docs.openclaw.ai/start/getting-started" rel="nofollow noopener noreferrer"&gt;Getting&lt;/a&gt;…&lt;/p&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/openclaw/openclaw" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h3&gt;
  
  
  Install Node.js 22+
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://deb.nodesource.com/setup_22.x | &lt;span class="nb"&gt;sudo&lt;/span&gt; &lt;span class="nt"&gt;-E&lt;/span&gt; bash -
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; nodejs
node &lt;span class="nt"&gt;--version&lt;/span&gt;  &lt;span class="c"&gt;# Should be v22+&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Install pnpm
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://get.pnpm.io/install.sh | sh -
&lt;span class="nb"&gt;source&lt;/span&gt; ~/.bashrc
pnpm &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Clone and build
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; ~/GIT &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd&lt;/span&gt; ~/GIT
git clone https://github.com/openclaw/openclaw.git
&lt;span class="nb"&gt;cd &lt;/span&gt;openclaw

&lt;span class="c"&gt;# Install dependencies&lt;/span&gt;
pnpm &lt;span class="nb"&gt;install&lt;/span&gt;

&lt;span class="c"&gt;# Build the UI and TypeScript&lt;/span&gt;
pnpm ui:build
pnpm build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Run the onboard wizard
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm openclaw onboard &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--non-interactive&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--accept-risk&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--flow&lt;/span&gt; quickstart &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--mode&lt;/span&gt; &lt;span class="nb"&gt;local&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--skip-channels&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--skip-skills&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--install-daemon&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;~/.openclaw/openclaw.json&lt;/code&gt; — main configuration&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;~/.openclaw/workspace/&lt;/code&gt; — agent workspace&lt;/li&gt;
&lt;li&gt;A systemd user service for the gateway&lt;/li&gt;
&lt;li&gt;Gateway listening on &lt;code&gt;127.0.0.1:18789&lt;/code&gt; (loopback only — not exposed!)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Verify it's running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm openclaw gateway status
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Gateway: bind=loopback (127.0.0.1), port=18789
Runtime: running (pid XXXXX)
RPC probe: ok
Dashboard: http://127.0.0.1:18789/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 3: Subscribe to Kimi Code and Get an API Key
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.kimi.com/code/en" rel="noopener noreferrer"&gt;Kimi Code&lt;/a&gt; is a subscription-based AI coding service by Moonshot AI. It powers the K2.5 model at up to 100 tokens/s and works with third-party tools like OpenClaw, Claude Code, and Roo Code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Subscribe
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Go to &lt;a href="https://www.kimi.com/code/en" rel="noopener noreferrer"&gt;kimi.com/code&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Log in or create an account&lt;/li&gt;
&lt;li&gt;Select a &lt;strong&gt;Coding Plan&lt;/strong&gt; (starts at ~$19/month for the Andante tier)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Your quota refreshes on a 7-day rolling cycle. Unused quota does not carry over.&lt;/p&gt;

&lt;h3&gt;
  
  
  Generate an API key
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Go to the &lt;a href="https://www.kimi.com/code/console" rel="noopener noreferrer"&gt;Kimi Code Console&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Navigate to &lt;strong&gt;API Keys&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Create New Key&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Copy the key immediately&lt;/strong&gt; — it's only shown once!&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Security note:&lt;/strong&gt; Treat your API key like a password. Never commit it to Git or expose it in client-side code. Kimi Code allows personal use in compatible third-party agents, but requests consume your subscription quota.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Step 4: Configure OpenClaw with Kimi Code
&lt;/h2&gt;

&lt;p&gt;Run the interactive config:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm openclaw config
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Select:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Model&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Moonshot AI&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Kimi Coding API key&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Paste your API key from the Kimi Code Console&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Or do it in one shot:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm openclaw onboard &lt;span class="nt"&gt;--kimi-code-api-key&lt;/span&gt; &lt;span class="s2"&gt;"YOUR_API_KEY"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Restart the gateway to apply:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm openclaw gateway restart
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Test it
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm openclaw agent &lt;span class="nt"&gt;--message&lt;/span&gt; &lt;span class="s2"&gt;"Hello! What model are you?"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should get a response from Kimi K2.5.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: Access the Dashboard
&lt;/h2&gt;

&lt;p&gt;The dashboard runs on &lt;code&gt;localhost:18789&lt;/code&gt; on the VPS. Since we locked down all ports, we access it through an SSH tunnel.&lt;/p&gt;

&lt;p&gt;From your local machine:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh &lt;span class="nt"&gt;-L&lt;/span&gt; 18789:localhost:18789 admin@YOUR_VPS_TAILSCALE_IP
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or with Tailscale SSH:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;tailscale ssh &lt;span class="nt"&gt;-L&lt;/span&gt; 18789:localhost:18789 admin@YOUR_VPS_TAILSCALE_IP
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now open your browser:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://localhost:18789/?token=YOUR_GATEWAY_TOKEN
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You'll find the gateway token in &lt;code&gt;~/.openclaw/openclaw.json&lt;/code&gt; under &lt;code&gt;gateway.auth.token&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The dashboard gives you a web UI to chat with your AI, manage sessions, configure channels, and more.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 6: Keep It Running
&lt;/h2&gt;

&lt;p&gt;The onboard wizard already installed a systemd user service. Make sure it survives reboots:&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;# Enable lingering so user services run without login&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;loginctl enable-linger admin

&lt;span class="c"&gt;# Check status&lt;/span&gt;
systemctl &lt;span class="nt"&gt;--user&lt;/span&gt; status openclaw-gateway
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Updating OpenClaw
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ~/GIT/openclaw
git pull &lt;span class="nt"&gt;--rebase&lt;/span&gt; origin main
pnpm &lt;span class="nb"&gt;install
&lt;/span&gt;pnpm ui:build
pnpm build
pnpm openclaw gateway restart
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Architecture Overview
&lt;/h2&gt;

&lt;p&gt;Here's what the final setup looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌─────────────────────────┐        ┌──────────────────────────┐
│   Your Machine          │        │   VPS (Ubuntu 24.04)     │
│                         │        │                          │
│  Browser ──SSH tunnel──────────────→ OpenClaw Gateway :18789│
│                         │        │   └── Kimi K2.5 API      │
│  Terminal               │        │   └── Workspace           │
│   └── tailscale ssh ──────────────→ Shell access             │
│                         │        │                          │
│  Tailscale ◄──WireGuard──────────►  Tailscale               │
└─────────────────────────┘        └──────────────────────────┘
                                   Firewall: ALL public ports CLOSED
                                   Only Tailscale (100.64.0.0/10) allowed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No public IP exposure. No open ports. No password authentication. Just a WireGuard tunnel and your AI assistant waiting on the other side.&lt;/p&gt;

&lt;h2&gt;
  
  
  Security Checklist
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[x] UFW firewall: deny all incoming except Tailscale&lt;/li&gt;
&lt;li&gt;[x] SSH: disabled (using Tailscale SSH instead)&lt;/li&gt;
&lt;li&gt;[x] Root login: disabled&lt;/li&gt;
&lt;li&gt;[x] Password auth: disabled&lt;/li&gt;
&lt;li&gt;[x] OpenClaw gateway: bound to loopback only&lt;/li&gt;
&lt;li&gt;[x] Dashboard access: via SSH tunnel only&lt;/li&gt;
&lt;li&gt;[x] API key: stored in server config, never exposed&lt;/li&gt;
&lt;li&gt;[x] Auto-updates: enabled on VPS&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Useful Commands
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Gateway management&lt;/span&gt;
pnpm openclaw gateway status
pnpm openclaw gateway restart
pnpm openclaw logs

&lt;span class="c"&gt;# Health check&lt;/span&gt;
pnpm openclaw doctor

&lt;span class="c"&gt;# Send a message&lt;/span&gt;
pnpm openclaw agent &lt;span class="nt"&gt;--message&lt;/span&gt; &lt;span class="s2"&gt;"Your message here"&lt;/span&gt;

&lt;span class="c"&gt;# List available models&lt;/span&gt;
pnpm openclaw models list

&lt;span class="c"&gt;# Reconfigure&lt;/span&gt;
pnpm openclaw config
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;For under $25/month (VPS + Kimi Code) you get a private AI assistant that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Runs 24/7 on your own hardware&lt;/li&gt;
&lt;li&gt;Is completely invisible to the internet&lt;/li&gt;
&lt;li&gt;Supports WhatsApp, Telegram, Slack, and dozens more channels&lt;/li&gt;
&lt;li&gt;Uses a powerful AI model (Kimi K2.5 via Kimi Code subscription)&lt;/li&gt;
&lt;li&gt;Remembers your conversations and preferences&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The hardest part was honestly debugging the WSL Tailscale MTU issue. Everything else was surprisingly smooth.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Resources:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/openclaw/openclaw" rel="noopener noreferrer"&gt;OpenClaw GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.openclaw.ai" rel="noopener noreferrer"&gt;OpenClaw Docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://tailscale.com" rel="noopener noreferrer"&gt;Tailscale&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.kimi.com/code/en" rel="noopener noreferrer"&gt;Kimi Code&lt;/a&gt; — subscribe and get your API key&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.kimi.com/code/console" rel="noopener noreferrer"&gt;Kimi Code Console&lt;/a&gt; — manage API keys and devices&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.kimi.com/code/docs/en/" rel="noopener noreferrer"&gt;Kimi Code Docs&lt;/a&gt; — membership benefits and usage details&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;strong&gt;Have you self-hosted an AI assistant? What's your setup? Let me know in the comments!&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>selfhosted</category>
      <category>security</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How to Install Moltbot with Docker and Gemini on WSL</title>
      <dc:creator>Nunc</dc:creator>
      <pubDate>Wed, 28 Jan 2026 11:37:09 +0000</pubDate>
      <link>https://dev.to/nunc/how-to-install-moltbot-with-docker-and-gemini-on-wsl-1aod</link>
      <guid>https://dev.to/nunc/how-to-install-moltbot-with-docker-and-gemini-on-wsl-1aod</guid>
      <description>&lt;p&gt;Ever wanted your own AI assistant that you can chat with via WhatsApp? Meet Moltbot - an open-source AI gateway that just went through a rebrand with an interesting backstory.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Name Change Story
&lt;/h2&gt;

&lt;p&gt;You might have heard of "Clawdbot" - a popular AI assistant project with a space lobster mascot. On January 27, 2026, Anthropic sent a trademark request because "Clawd" was too similar to their "Claude" trademark.&lt;/p&gt;

&lt;p&gt;Creator Peter Steinberger (@steipete) took it in stride:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Anthropic asked us to change our name (trademark stuff), and honestly? 'Molt' fits perfectly - it's what lobsters do to grow."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The mascot is now "Molty" and the project is "Moltbot". Sometimes forced changes lead to better names.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Gemini Instead of Claude?
&lt;/h2&gt;

&lt;p&gt;You might wonder: "I have a Claude Code subscription, why not use that?"&lt;/p&gt;

&lt;p&gt;Here's the problem: &lt;strong&gt;Anthropic actively blocks third-party tools from using Claude Code subscriptions&lt;/strong&gt;, and doing so violates their Terms of Service.&lt;/p&gt;

&lt;p&gt;In early January 2026, Anthropic &lt;a href="https://piunikaweb.com/2026/01/09/anthropic-reportedly-blocking-non-official-claude-api-connections/" rel="noopener noreferrer"&gt;cracked down on "harnesses"&lt;/a&gt; - third-party tools that use Claude Code OAuth to access consumer subscriptions. An Anthropic employee explained:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Restrictions target third-party harnesses spoofing the official client, which violate ToS by creating unusual traffic patterns without telemetry — complicating debugging, rate limits, and support."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The risks of using Claude Code subscription with Moltbot:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Risk&lt;/th&gt;
&lt;th&gt;Details&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Account ban&lt;/td&gt;
&lt;td&gt;Anthropic has banned users for TOS violations&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sudden disconnection&lt;/td&gt;
&lt;td&gt;Your bot stops working without warning&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gray area legally&lt;/td&gt;
&lt;td&gt;Operating outside official support&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The error you'll see: &lt;em&gt;"This credential is only authorized for use with Claude Code and cannot be used for other API requests."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The safe alternatives:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Gemini CLI&lt;/strong&gt; (this guide) - Free tier, legitimate OAuth&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Anthropic API key&lt;/strong&gt; - Pay-as-you-go, officially supported&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Google Antigravity&lt;/strong&gt; - Access Claude via Google's infrastructure&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This guide uses Gemini because it's free, has generous limits, and Google actively supports third-party integrations.&lt;/p&gt;

&lt;h2&gt;
  
  
  What You'll Build
&lt;/h2&gt;

&lt;p&gt;By the end of this guide, you'll have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Moltbot running in Docker on WSL&lt;/li&gt;
&lt;li&gt;Google Gemini as your AI backend (free tier available)&lt;/li&gt;
&lt;li&gt;Optional WhatsApp integration to chat with your bot&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Windows with WSL 2 (Ubuntu 22.04)&lt;/li&gt;
&lt;li&gt;An internet connection&lt;/li&gt;
&lt;li&gt;About 30 minutes&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 1: Install Docker in WSL
&lt;/h2&gt;

&lt;p&gt;Open your WSL terminal and run:&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;# Update and install dependencies&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get update
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; ca-certificates curl gnupg

&lt;span class="c"&gt;# Add Docker's GPG key&lt;/span&gt;
&lt;span class="nb"&gt;sudo install&lt;/span&gt; &lt;span class="nt"&gt;-m&lt;/span&gt; 0755 &lt;span class="nt"&gt;-d&lt;/span&gt; /etc/apt/keyrings
curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://download.docker.com/linux/ubuntu/gpg | &lt;span class="nb"&gt;sudo &lt;/span&gt;gpg &lt;span class="nt"&gt;--dearmor&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; /etc/apt/keyrings/docker.gpg
&lt;span class="nb"&gt;sudo chmod &lt;/span&gt;a+r /etc/apt/keyrings/docker.gpg

&lt;span class="c"&gt;# Add Docker repository&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"deb [arch=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;dpkg &lt;span class="nt"&gt;--print-architecture&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt; signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu &lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt; /etc/os-release &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$VERSION_CODENAME&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt; stable"&lt;/span&gt; | &lt;span class="nb"&gt;sudo tee&lt;/span&gt; /etc/apt/sources.list.d/docker.list &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /dev/null

&lt;span class="c"&gt;# Install Docker Engine&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get update
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

&lt;span class="c"&gt;# Add yourself to docker group&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;usermod &lt;span class="nt"&gt;-aG&lt;/span&gt; docker &lt;span class="nv"&gt;$USER&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;service docker start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; Log out of WSL and back in for the group change to work:&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="nb"&gt;exit&lt;/span&gt;
&lt;span class="c"&gt;# Reopen WSL, then verify:&lt;/span&gt;
docker run hello-world
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 2: Clone and Build Moltbot
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; ~/GIT/moltbot-project
&lt;span class="nb"&gt;cd&lt;/span&gt; ~/GIT/moltbot-project
git clone https://github.com/moltbot/moltbot.git
&lt;span class="nb"&gt;cd &lt;/span&gt;moltbot
./docker-setup.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;During setup, use these quick settings:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Prompt&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Security warning&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Onboarding mode&lt;/td&gt;
&lt;td&gt;QuickStart&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Model/auth provider&lt;/td&gt;
&lt;td&gt;Skip for now&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gateway bind&lt;/td&gt;
&lt;td&gt;lan&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gateway auth&lt;/td&gt;
&lt;td&gt;token&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Step 3: Add Gemini Support
&lt;/h2&gt;

&lt;p&gt;Create a custom Dockerfile that includes Gemini CLI:&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="nb"&gt;cd&lt;/span&gt; ~/GIT/moltbot-project

&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; Dockerfile.custom &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;'
FROM moltbot:local
USER root
RUN npm install -g @google/gemini-cli
USER node
VOLUME /home/node/.gemini
&lt;/span&gt;&lt;span class="no"&gt;EOF

&lt;/span&gt;docker build &lt;span class="nt"&gt;-t&lt;/span&gt; moltbot-with-gemini &lt;span class="nt"&gt;-f&lt;/span&gt; Dockerfile.custom &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 4: Authenticate with Gemini
&lt;/h2&gt;

&lt;p&gt;Install and authenticate Gemini CLI in WSL:&lt;br&gt;
&lt;/p&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; &lt;span class="nt"&gt;-g&lt;/span&gt; @google/gemini-cli
gemini
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Follow the OAuth flow in your browser. This creates credentials in &lt;code&gt;~/.gemini/&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: Wire It All Together
&lt;/h2&gt;

&lt;p&gt;Create a Docker Compose override to mount your Gemini credentials:&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="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; ~/GIT/moltbot-project/moltbot/docker-compose.override.yml &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;'
services:
  moltbot-gateway:
    image: moltbot-with-gemini
    environment:
      HOME: /home/node
    volumes:
      - ~/.gemini:/home/node/.gemini
      - ~/.clawdbot:/home/node/.moltbot
  moltbot-cli:
    image: moltbot-with-gemini
    environment:
      HOME: /home/node
    volumes:
      - ~/.gemini:/home/node/.gemini
      - ~/.clawdbot:/home/node/.moltbot
&lt;/span&gt;&lt;span class="no"&gt;EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Enable the Gemini plugin:&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="nb"&gt;cd&lt;/span&gt; ~/GIT/moltbot-project/moltbot

&lt;span class="c"&gt;# Enable plugin&lt;/span&gt;
docker compose &lt;span class="nt"&gt;-f&lt;/span&gt; docker-compose.yml &lt;span class="nt"&gt;-f&lt;/span&gt; docker-compose.override.yml run &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nt"&gt;--rm&lt;/span&gt; moltbot-cli plugins &lt;span class="nb"&gt;enable &lt;/span&gt;google-gemini-cli-auth

&lt;span class="c"&gt;# Authenticate inside container&lt;/span&gt;
docker compose &lt;span class="nt"&gt;-f&lt;/span&gt; docker-compose.yml &lt;span class="nt"&gt;-f&lt;/span&gt; docker-compose.override.yml run &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nt"&gt;--rm&lt;/span&gt; moltbot-cli auth login &lt;span class="nt"&gt;--provider&lt;/span&gt; google-gemini-cli

&lt;span class="c"&gt;# Configure models&lt;/span&gt;
docker compose &lt;span class="nt"&gt;-f&lt;/span&gt; docker-compose.yml &lt;span class="nt"&gt;-f&lt;/span&gt; docker-compose.override.yml run &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nt"&gt;--rm&lt;/span&gt; moltbot-cli configure
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 6: Start and Test
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Start the gateway&lt;/span&gt;
docker compose &lt;span class="nt"&gt;-f&lt;/span&gt; docker-compose.yml &lt;span class="nt"&gt;-f&lt;/span&gt; docker-compose.override.yml up &lt;span class="nt"&gt;-d&lt;/span&gt; moltbot-gateway

&lt;span class="c"&gt;# Test it&lt;/span&gt;
docker compose &lt;span class="nt"&gt;-f&lt;/span&gt; docker-compose.yml &lt;span class="nt"&gt;-f&lt;/span&gt; docker-compose.override.yml run &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nt"&gt;--rm&lt;/span&gt; moltbot-cli agent &lt;span class="nt"&gt;--local&lt;/span&gt; &lt;span class="nt"&gt;--session-id&lt;/span&gt; &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Hello!"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should get a response from your AI.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bonus: Add WhatsApp
&lt;/h2&gt;

&lt;p&gt;WhatsApp is surprisingly easy - it uses QR code login like WhatsApp Web.&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;# Configure WhatsApp channel&lt;/span&gt;
docker compose &lt;span class="nt"&gt;-f&lt;/span&gt; docker-compose.yml &lt;span class="nt"&gt;-f&lt;/span&gt; docker-compose.override.yml run &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nt"&gt;--rm&lt;/span&gt; moltbot-cli configure
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Select &lt;strong&gt;Channels&lt;/strong&gt; -&amp;gt; &lt;strong&gt;WhatsApp&lt;/strong&gt; and set:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Personal phone mode: Yes&lt;/li&gt;
&lt;li&gt;dmPolicy: allowlist&lt;/li&gt;
&lt;li&gt;allowFrom: Your phone number (e.g., +15551234567)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then link your phone:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker compose &lt;span class="nt"&gt;-f&lt;/span&gt; docker-compose.yml &lt;span class="nt"&gt;-f&lt;/span&gt; docker-compose.override.yml run &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nt"&gt;--rm&lt;/span&gt; moltbot-cli channels login
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Scan the QR code with WhatsApp (Settings -&amp;gt; Linked Devices -&amp;gt; Link a Device). Now you can chat with your AI via WhatsApp self-messages.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick Reference Commands
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ~/GIT/moltbot-project/moltbot

&lt;span class="c"&gt;# Start&lt;/span&gt;
docker compose &lt;span class="nt"&gt;-f&lt;/span&gt; docker-compose.yml &lt;span class="nt"&gt;-f&lt;/span&gt; docker-compose.override.yml up &lt;span class="nt"&gt;-d&lt;/span&gt; moltbot-gateway

&lt;span class="c"&gt;# Stop&lt;/span&gt;
docker compose &lt;span class="nt"&gt;-f&lt;/span&gt; docker-compose.yml &lt;span class="nt"&gt;-f&lt;/span&gt; docker-compose.override.yml down

&lt;span class="c"&gt;# View logs&lt;/span&gt;
docker compose &lt;span class="nt"&gt;-f&lt;/span&gt; docker-compose.yml &lt;span class="nt"&gt;-f&lt;/span&gt; docker-compose.override.yml logs &lt;span class="nt"&gt;-f&lt;/span&gt; moltbot-gateway

&lt;span class="c"&gt;# Open dashboard&lt;/span&gt;
docker compose &lt;span class="nt"&gt;-f&lt;/span&gt; docker-compose.yml &lt;span class="nt"&gt;-f&lt;/span&gt; docker-compose.override.yml run &lt;span class="nt"&gt;--rm&lt;/span&gt; moltbot-cli dashboard
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Troubleshooting
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Docker permission denied?&lt;/strong&gt;&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="nb"&gt;sudo &lt;/span&gt;usermod &lt;span class="nt"&gt;-aG&lt;/span&gt; docker &lt;span class="nv"&gt;$USER&lt;/span&gt;
&lt;span class="c"&gt;# Then log out and back in&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Gemini rate limits (429)?&lt;/strong&gt;&lt;br&gt;
The free tier has limits. Wait a bit or add an API key fallback from &lt;a href="https://aistudio.google.com/" rel="noopener noreferrer"&gt;Google AI Studio&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Config files owned by root?&lt;/strong&gt;&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="nb"&gt;sudo chown&lt;/span&gt; &lt;span class="nt"&gt;-R&lt;/span&gt; &lt;span class="nv"&gt;$USER&lt;/span&gt;:&lt;span class="nv"&gt;$USER&lt;/span&gt; ~/.clawdbot
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;Moltbot gives you a self-hosted AI gateway that can connect to various backends (Gemini, Claude via Antigravity, etc.) and channels (WhatsApp, Discord, Telegram). The Docker setup keeps everything contained and reproducible.&lt;/p&gt;

&lt;p&gt;The rebrand from Clawdbot to Moltbot is a good reminder that sometimes external pressure leads to better outcomes - "Molt" really does fit the lobster theme better.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Have you set up Moltbot or a similar AI assistant? Share your experience in the comments!&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>docker</category>
      <category>wsl</category>
      <category>ai</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How to Run Clawdbot on WSL with Your Claude Code Subscription</title>
      <dc:creator>Nunc</dc:creator>
      <pubDate>Mon, 26 Jan 2026 13:33:45 +0000</pubDate>
      <link>https://dev.to/nunc/how-to-run-clawdbot-on-wsl-with-your-claude-code-subscription-13i4</link>
      <guid>https://dev.to/nunc/how-to-run-clawdbot-on-wsl-with-your-claude-code-subscription-13i4</guid>
      <description>&lt;p&gt;I wanted to run Clawdbot—an AI chatbot framework—on Windows WSL, but there was a catch: I needed to use my existing Claude Code subscription instead of paying for separate API access. Here's how I got it working.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Authentication Challenge
&lt;/h2&gt;

&lt;p&gt;Clawdbot supports multiple authentication methods, but most require paid API access. If you have a Claude Code subscription, you can leverage its OAuth mechanism instead. The trick? Claude Code CLI must be &lt;strong&gt;inside&lt;/strong&gt; the Docker container.&lt;/p&gt;

&lt;p&gt;Here's why this setup is required:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Requirement&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Claude Code CLI in container&lt;/td&gt;
&lt;td&gt;Clawdbot uses Claude Code's OAuth mechanism&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mount &lt;code&gt;~/.claude&lt;/code&gt; credentials&lt;/td&gt;
&lt;td&gt;Where Claude Code stores authentication&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Set &lt;code&gt;HOME=/home/node&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;So Claude Code finds the credentials&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Other auth methods won't work with your subscription:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Anthropic API key requires paid API access&lt;/li&gt;
&lt;li&gt;Setup-token paste has incompatible format&lt;/li&gt;
&lt;li&gt;Claude Code CLI OAuth uses your subscription&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before starting, make sure you have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Windows with WSL 2 (Ubuntu 22.04)&lt;/li&gt;
&lt;li&gt;Claude Code CLI installed and authenticated in WSL&lt;/li&gt;
&lt;li&gt;Internet connection&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you haven't installed Claude Code yet:&lt;br&gt;
&lt;/p&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; &lt;span class="nt"&gt;-g&lt;/span&gt; @anthropic-ai/claude-code &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; claude
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Step 1: Install Docker Engine in WSL
&lt;/h2&gt;

&lt;p&gt;First, set up Docker in your WSL environment:&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;# Update package index&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get update

&lt;span class="c"&gt;# Install required packages&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; ca-certificates curl gnupg

&lt;span class="c"&gt;# Add Docker's official GPG key&lt;/span&gt;
&lt;span class="nb"&gt;sudo install&lt;/span&gt; &lt;span class="nt"&gt;-m&lt;/span&gt; 0755 &lt;span class="nt"&gt;-d&lt;/span&gt; /etc/apt/keyrings
curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://download.docker.com/linux/ubuntu/gpg | &lt;span class="nb"&gt;sudo &lt;/span&gt;gpg &lt;span class="nt"&gt;--dearmor&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; /etc/apt/keyrings/docker.gpg
&lt;span class="nb"&gt;sudo chmod &lt;/span&gt;a+r /etc/apt/keyrings/docker.gpg

&lt;span class="c"&gt;# Add Docker repository&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"deb [arch=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;dpkg &lt;span class="nt"&gt;--print-architecture&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt; signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu &lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt; /etc/os-release &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$VERSION_CODENAME&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt; stable"&lt;/span&gt; | &lt;span class="nb"&gt;sudo tee&lt;/span&gt; /etc/apt/sources.list.d/docker.list &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /dev/null

&lt;span class="c"&gt;# Install Docker Engine&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get update
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

&lt;span class="c"&gt;# Add your user to docker group&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;usermod &lt;span class="nt"&gt;-aG&lt;/span&gt; docker &lt;span class="nv"&gt;$USER&lt;/span&gt;

&lt;span class="c"&gt;# Start Docker service&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;service docker start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Log out and back into WSL for the group change to take effect, then verify:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nt"&gt;--version&lt;/span&gt;
docker compose version
docker run hello-world
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Step 2: Clone and Build Clawdbot
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; ~/GIT/clawdbot-project
&lt;span class="nb"&gt;cd&lt;/span&gt; ~/GIT/clawdbot-project
git clone https://github.com/clawdbot/clawdbot.git
&lt;span class="nb"&gt;cd &lt;/span&gt;clawdbot
./docker-setup.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;During the onboarding prompts, use these settings:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Prompt&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Security warning&lt;/td&gt;
&lt;td&gt;Yes (continue)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Onboarding mode&lt;/td&gt;
&lt;td&gt;QuickStart&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Model/auth provider&lt;/td&gt;
&lt;td&gt;Skip for now&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gateway bind&lt;/td&gt;
&lt;td&gt;lan&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gateway auth&lt;/td&gt;
&lt;td&gt;token&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Skills&lt;/td&gt;
&lt;td&gt;Skip for now&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hooks&lt;/td&gt;
&lt;td&gt;Skip for now&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h2&gt;
  
  
  Step 3: Build Custom Image with Claude Code
&lt;/h2&gt;

&lt;p&gt;Here's the key part. Create a custom Dockerfile that includes Claude Code CLI:&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="nb"&gt;cd&lt;/span&gt; ~/GIT/clawdbot-project

&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; Dockerfile.custom &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;'
FROM clawdbot:local

# Install Claude Code CLI
RUN npm install -g @anthropic-ai/claude-code

# Mount point for Claude credentials
VOLUME /home/node/.claude
&lt;/span&gt;&lt;span class="no"&gt;EOF

&lt;/span&gt;docker build &lt;span class="nt"&gt;-t&lt;/span&gt; clawdbot-with-claude &lt;span class="nt"&gt;-f&lt;/span&gt; Dockerfile.custom &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Step 4: Create Docker Compose Override
&lt;/h2&gt;

&lt;p&gt;Create an override file to use the custom image and mount your Claude credentials:&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="c1"&gt;# ~/GIT/clawdbot-project/clawdbot/docker-compose.override.yml&lt;/span&gt;
&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;clawdbot-gateway&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;clawdbot-with-claude&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;HOME&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/home/node&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;~/.claude:/home/node/.claude&lt;/span&gt;
  &lt;span class="na"&gt;clawdbot-cli&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;clawdbot-with-claude&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;HOME&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/home/node&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;~/.claude:/home/node/.claude&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Save this to &lt;code&gt;~/GIT/clawdbot-project/clawdbot/docker-compose.override.yml&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 5: Configure Dashboard Access
&lt;/h2&gt;

&lt;p&gt;Enable insecure auth for local dashboard access by editing &lt;code&gt;~/.clawdbot/clawdbot.json&lt;/code&gt;. Add this inside the &lt;code&gt;"gateway"&lt;/code&gt; section:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"controlUi"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"allowInsecureAuth"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Also change &lt;code&gt;"bind": "loopback"&lt;/code&gt; to &lt;code&gt;"bind": "lan"&lt;/code&gt; if you want to access it from your network.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 6: Start and Test
&lt;/h2&gt;

&lt;p&gt;Start the gateway:&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="nb"&gt;cd&lt;/span&gt; ~/GIT/clawdbot-project/clawdbot
docker compose &lt;span class="nt"&gt;-f&lt;/span&gt; docker-compose.yml &lt;span class="nt"&gt;-f&lt;/span&gt; docker-compose.override.yml up &lt;span class="nt"&gt;-d&lt;/span&gt; clawdbot-gateway
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Test the agent:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker compose &lt;span class="nt"&gt;-f&lt;/span&gt; docker-compose.yml &lt;span class="nt"&gt;-f&lt;/span&gt; docker-compose.override.yml run &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nt"&gt;--rm&lt;/span&gt; clawdbot-cli agent &lt;span class="nt"&gt;--local&lt;/span&gt; &lt;span class="nt"&gt;--session-id&lt;/span&gt; &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Hello!"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;You should get a response from Claude.&lt;/p&gt;
&lt;h2&gt;
  
  
  Accessing the Dashboard
&lt;/h2&gt;

&lt;p&gt;Get your gateway token:&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="nb"&gt;grep &lt;/span&gt;CLAWDBOT_GATEWAY_TOKEN ~/GIT/clawdbot-project/clawdbot/.env
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Then open &lt;code&gt;http://127.0.0.1:18789/?token=YOUR_TOKEN_HERE&lt;/code&gt; in your browser.&lt;/p&gt;
&lt;h2&gt;
  
  
  Bonus: Adding WhatsApp
&lt;/h2&gt;

&lt;p&gt;WhatsApp is surprisingly easy to set up—it uses QR code login like WhatsApp Web.&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="nb"&gt;cd&lt;/span&gt; ~/GIT/clawdbot-project/clawdbot
docker compose &lt;span class="nt"&gt;-f&lt;/span&gt; docker-compose.yml &lt;span class="nt"&gt;-f&lt;/span&gt; docker-compose.override.yml run &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nt"&gt;--rm&lt;/span&gt; clawdbot-cli configure
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Select &lt;strong&gt;Channels&lt;/strong&gt; → &lt;strong&gt;WhatsApp&lt;/strong&gt; and configure:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Personal phone mode: Yes&lt;/li&gt;
&lt;li&gt;dmPolicy: allowlist&lt;/li&gt;
&lt;li&gt;allowFrom: Your phone number (E.164 format like +1555123456)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then link your phone:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker compose &lt;span class="nt"&gt;-f&lt;/span&gt; docker-compose.yml &lt;span class="nt"&gt;-f&lt;/span&gt; docker-compose.override.yml run &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nt"&gt;--rm&lt;/span&gt; clawdbot-cli channels login
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Scan the QR code with WhatsApp → Settings → Linked Devices → Link a Device.&lt;/p&gt;
&lt;h2&gt;
  
  
  Quick Reference Commands
&lt;/h2&gt;

&lt;p&gt;&lt;/p&gt;
  Click to expand common commands
  &lt;br&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Start gateway&lt;/span&gt;
docker compose &lt;span class="nt"&gt;-f&lt;/span&gt; docker-compose.yml &lt;span class="nt"&gt;-f&lt;/span&gt; docker-compose.override.yml up &lt;span class="nt"&gt;-d&lt;/span&gt; clawdbot-gateway

&lt;span class="c"&gt;# Stop gateway&lt;/span&gt;
docker compose &lt;span class="nt"&gt;-f&lt;/span&gt; docker-compose.yml &lt;span class="nt"&gt;-f&lt;/span&gt; docker-compose.override.yml down

&lt;span class="c"&gt;# View logs&lt;/span&gt;
docker compose &lt;span class="nt"&gt;-f&lt;/span&gt; docker-compose.yml &lt;span class="nt"&gt;-f&lt;/span&gt; docker-compose.override.yml logs &lt;span class="nt"&gt;-f&lt;/span&gt; clawdbot-gateway

&lt;span class="c"&gt;# Test agent&lt;/span&gt;
docker compose &lt;span class="nt"&gt;-f&lt;/span&gt; docker-compose.yml &lt;span class="nt"&gt;-f&lt;/span&gt; docker-compose.override.yml run &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nt"&gt;--rm&lt;/span&gt; clawdbot-cli agent &lt;span class="nt"&gt;--local&lt;/span&gt; &lt;span class="nt"&gt;--session-id&lt;/span&gt; &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Hello"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;p&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Troubleshooting
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Docker permission denied:&lt;/strong&gt; Run &lt;code&gt;sudo usermod -aG docker $USER&lt;/code&gt; and log out/in.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Claude credentials not working:&lt;/strong&gt; Re-authenticate with &lt;code&gt;claude /login&lt;/code&gt; in WSL.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dashboard shows "pairing required":&lt;/strong&gt; Ensure &lt;code&gt;controlUi.allowInsecureAuth: true&lt;/code&gt; is in your config.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No response from agent:&lt;/strong&gt; Check that &lt;code&gt;HOME=/home/node&lt;/code&gt; is set and &lt;code&gt;~/.claude&lt;/code&gt; is mounted in your override file.&lt;/p&gt;
&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;The key insight here is that Claude Code's OAuth tokens can be shared with containerized applications by mounting the credentials directory. This pattern works for any Docker-based tool that supports Claude Code authentication.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/openclaw" rel="noopener noreferrer"&gt;
        openclaw
      &lt;/a&gt; / &lt;a href="https://github.com/openclaw/openclaw" rel="noopener noreferrer"&gt;
        openclaw
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Your own personal AI assistant. Any OS. Any Platform. The lobster way. 🦞 
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;🦞 OpenClaw — Personal AI Assistant&lt;/h1&gt;
&lt;/div&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%2Fraw.githubusercontent.com%2Fopenclaw%2Fopenclaw%2Fmain%2Fdocs%2Fassets%2Fopenclaw-banner-dark.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%2Fraw.githubusercontent.com%2Fopenclaw%2Fopenclaw%2Fmain%2Fdocs%2Fassets%2Fopenclaw-banner-dark.png" alt="OpenClaw — EXFOLIATE! EXFOLIATE! Your personal AI assistant, running on your own devices."&gt;&lt;/a&gt;
    
&lt;/p&gt;

&lt;p&gt;
  &lt;a href="https://github.com/openclaw/openclaw/actions/workflows/ci.yml?branch=main" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/1ddb1ef286e297deafb2a4372b7c65516ae65368fd22878a7454dabc2fc4738b/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f6f70656e636c61772f6f70656e636c61772f63692e796d6c3f6272616e63683d6d61696e267374796c653d666f722d7468652d6261646765" alt="CI status"&gt;&lt;/a&gt;
  &lt;a href="https://github.com/openclaw/openclaw/releases" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/9fcbb4c3c5cf1f8657a73e45b9c76a0074008d658c07f5558e474191c7aef8fb/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f762f72656c656173652f6f70656e636c61772f6f70656e636c61773f696e636c7564655f70726572656c6561736573267374796c653d666f722d7468652d6261646765" alt="GitHub release"&gt;&lt;/a&gt;
  &lt;a href="https://discord.gg/clawd" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/1860c01c5ab9a20c37ea5a09fcf7ea1471eb95ed7095bb99d3c5a7331061ccda/68747470733a2f2f696d672e736869656c64732e696f2f646973636f72642f313435363335303036343036353930343836373f6c6162656c3d446973636f7264266c6f676f3d646973636f7264266c6f676f436f6c6f723d776869746526636f6c6f723d353836354632267374796c653d666f722d7468652d6261646765" alt="Discord"&gt;&lt;/a&gt;
  &lt;a href="https://github.com/openclaw/openclaw/LICENSE" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/608c8dfda488178950ce502d7697514db3a6a712579327ed90b9b594260f6355/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6963656e73652d4d49542d626c75652e7376673f7374796c653d666f722d7468652d6261646765" alt="MIT License"&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;OpenClaw&lt;/strong&gt; is a &lt;em&gt;personal AI assistant&lt;/em&gt; that learns and grows with you, running on your own devices — developed in the open by the OpenClaw Foundation (a non-profit)
It answers you on the channels you already use. It can speak and listen on macOS/iOS/Android, and can render a live Canvas you control. The Gateway is just the control plane — the product is the assistant.&lt;/p&gt;
&lt;p&gt;If you want a personal, single-user assistant that feels local, fast, and always-on, this is it.&lt;/p&gt;
&lt;p&gt;Supported channels include: WhatsApp, Telegram, Slack, Discord, Google Chat, Signal, iMessage, IRC, Microsoft Teams, Matrix, Feishu, LINE, Mattermost, Nextcloud Talk, Nostr, Synology Chat, Tlon, Twitch, Zalo, Zalo Personal, WeChat, QQ, WebChat.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://openclaw.ai" rel="nofollow noopener noreferrer"&gt;Website&lt;/a&gt; · &lt;a href="https://docs.openclaw.ai" rel="nofollow noopener noreferrer"&gt;Docs&lt;/a&gt; · &lt;a href="https://github.com/openclaw/openclaw/VISION.md" rel="noopener noreferrer"&gt;Vision&lt;/a&gt; · &lt;a href="https://github.com/openclaw/openclaw/THIRD_PARTY_NOTICES.md" rel="noopener noreferrer"&gt;Third-party notices&lt;/a&gt; · &lt;a href="https://deepwiki.com/openclaw/openclaw" rel="nofollow noopener noreferrer"&gt;DeepWiki&lt;/a&gt; · &lt;a href="https://docs.openclaw.ai/start/getting-started" rel="nofollow noopener noreferrer"&gt;Getting Started&lt;/a&gt; · &lt;a href="https://docs.openclaw.ai/install/updating" rel="nofollow noopener noreferrer"&gt;Updating&lt;/a&gt; · &lt;a href="https://docs.openclaw.ai/start/showcase" rel="nofollow noopener noreferrer"&gt;Showcase&lt;/a&gt; · &lt;a href="https://docs.openclaw.ai/help/faq" rel="nofollow noopener noreferrer"&gt;FAQ&lt;/a&gt; · &lt;a href="https://docs.openclaw.ai/start/wizard" rel="nofollow noopener noreferrer"&gt;Onboarding&lt;/a&gt; · &lt;a href="https://github.com/openclaw/nix-openclaw" rel="noopener noreferrer"&gt;Nix&lt;/a&gt; · &lt;a href="https://docs.openclaw.ai/install/docker" rel="nofollow noopener noreferrer"&gt;Docker&lt;/a&gt; · &lt;a href="https://discord.gg/clawd" rel="nofollow noopener noreferrer"&gt;Discord&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;New install? Start here: &lt;a href="https://docs.openclaw.ai/start/getting-started" rel="nofollow noopener noreferrer"&gt;Getting&lt;/a&gt;…&lt;/p&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/openclaw/openclaw" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;





&lt;p&gt;&lt;strong&gt;Have you tried running AI assistants in Docker? What authentication challenges did you face? Share in the comments!&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>docker</category>
      <category>wsl</category>
      <category>ai</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>I Used Claude Code to Write a Legal Appeal for My Mother's Disability Benefits</title>
      <dc:creator>Nunc</dc:creator>
      <pubDate>Fri, 23 Jan 2026 09:01:47 +0000</pubDate>
      <link>https://dev.to/nunc/i-used-claude-code-to-write-a-legal-appeal-for-my-mothers-disability-benefits-40f4</link>
      <guid>https://dev.to/nunc/i-used-claude-code-to-write-a-legal-appeal-for-my-mothers-disability-benefits-40f4</guid>
      <description>&lt;p&gt;I'm a software developer. Claude Code is a CLI tool designed for coding tasks - writing code, debugging, refactoring. So naturally, I used it to write a 230-line legal appeal against a government disability decision.&lt;/p&gt;

&lt;p&gt;Here's how a programming tool became my most powerful ally in a deeply personal, completely non-technical challenge.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;My mother has severe spinal degeneration. After 45 years of physically demanding work, multiple surgeries, and recent osteoporotic vertebral fractures, she applied for disability benefits and care allowance from the national pension and disability insurance agency.&lt;/p&gt;

&lt;p&gt;The response? &lt;strong&gt;Rejected.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The expert medical commission concluded:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Her spine condition was "congenital" (born with it)&lt;/li&gt;
&lt;li&gt;Treatment was "completed"&lt;/li&gt;
&lt;li&gt;She could perform daily activities independently&lt;/li&gt;
&lt;li&gt;Only 30% disability recognized (50% required for benefits)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Reading the decision, I knew it was wrong. But how do you argue against a medical commission with mountains of paperwork, complex regulations, and 25+ years of medical history?&lt;/p&gt;

&lt;h2&gt;
  
  
  The Chaos: 50+ Scanned Medical Documents
&lt;/h2&gt;

&lt;p&gt;My mother's medical history was a nightmare to navigate:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;spine-findings/           # Spine-related medical records (12 files)
additional-findings/      # Additional medical findings (8 files)
application-docs/         # Original application attachments (15 files)
new-findings-2026/        # Recent findings from January 2026 (20+ files)
commission-opinion/       # The commission's expert opinion (6 files)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All scanned as JPG images. Handwritten doctor's notes from 1998. Faded hospital discharge papers. CT scan reports. Years of medical history trapped in pixels.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: OCR with Google Gemini API
&lt;/h2&gt;

&lt;p&gt;First challenge: extract text from images.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Side note:&lt;/strong&gt; Claude Code can also read images and perform OCR directly. However, for bulk processing of 50+ scanned medical documents - many with handwritten notes and faded text from the 1990s - Google's Gemini with "thinking mode" produced significantly better results. Claude Code's OCR is decent for quick reads, but Gemini's accuracy on difficult documents was noticeably superior.&lt;/p&gt;

&lt;p&gt;I wrote a simple Python script using Google's Gemini API:&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;google&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;genai&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;google.genai&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;types&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;extract_text_from_image&lt;/span&gt;&lt;span class="p"&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;image_path&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;image_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rb&lt;/span&gt;&lt;span class="sh"&gt;"&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;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;image_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;contents&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="n"&gt;types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Content&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;role&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;parts&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
                &lt;span class="n"&gt;types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Part&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_bytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                    &lt;span class="n"&gt;mime_type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;image/jpeg&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;image_data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="n"&gt;types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Part&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                    &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Extract all text from this image. &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
                         &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Preserve formatting and structure. &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
                         &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;If handwritten, transcribe to readable form.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
                &lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="c1"&gt;# Using Gemini's thinking mode for better accuracy
&lt;/span&gt;    &lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;GenerateContentConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;thinking_config&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ThinkingConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;thinking_level&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;HIGH&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&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;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate_content_stream&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;gemini-3-pro-preview&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;contents&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;contents&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&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;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&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;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The script processed entire folders:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python extract_ocr.py &lt;span class="s2"&gt;"new-findings-2026/"&lt;/span&gt;
&lt;span class="c"&gt;# Found 24 images without TXT:&lt;/span&gt;
&lt;span class="c"&gt;#   - scan_001.jpg&lt;/span&gt;
&lt;span class="c"&gt;#   - scan_002.jpg&lt;/span&gt;
&lt;span class="c"&gt;#   ...&lt;/span&gt;
&lt;span class="c"&gt;# Processing: scan_001.jpg... OK -&amp;gt; scan_001.txt&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Result: Every medical document now had a searchable &lt;code&gt;.txt&lt;/code&gt; companion file.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Building Context with CLAUDE.md
&lt;/h2&gt;

&lt;p&gt;Claude Code uses a &lt;code&gt;CLAUDE.md&lt;/code&gt; file for project-specific context. I created one explaining the case:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# CLAUDE.md&lt;/span&gt;

&lt;span class="gu"&gt;## Repository Purpose&lt;/span&gt;

Document repository for a disability benefits appeal case.

&lt;span class="gu"&gt;## Document Structure&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; &lt;span class="gs"&gt;**spine-findings/**&lt;/span&gt; - Spine medical records (JPG + OCR'd TXT)
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="gs"&gt;**commission-opinion/**&lt;/span&gt; - Expert commission documents
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="gs"&gt;**appeal-drafts/**&lt;/span&gt; - Appeal document versions

&lt;span class="gu"&gt;## Key Context for Appeal&lt;/span&gt;

Main contested points from the expert opinion:
&lt;span class="p"&gt;-&lt;/span&gt; Health history incorrectly characterized as congenital
&lt;span class="p"&gt;-&lt;/span&gt; Treatment incorrectly marked as concluded
&lt;span class="p"&gt;-&lt;/span&gt; Independence incorrectly assessed
&lt;span class="p"&gt;-&lt;/span&gt; New osteoporotic fractures not considered
&lt;span class="p"&gt;-&lt;/span&gt; Date of injury incorrectly stated

&lt;span class="gu"&gt;## Working with Documents&lt;/span&gt;

Read .txt versions for text content.
Reference official disability regulations for legal basis.
Use formal legal/medical terminology.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now Claude Code understood the project structure and goals.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: The Iterative Writing Process
&lt;/h2&gt;

&lt;p&gt;This is where Claude Code shined. I started with rough notes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;I disagree with the expert opinion because:
- My condition isn't congenital - first problems at age 51
- Treatment ongoing - have orthopedic appointment scheduled
- Can't cook, clean, or do laundry independently
- New vertebral fractures in 2025 weren't considered
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Claude Code read all the OCR'd medical files, cross-referenced dates and diagnoses, and produced the first draft. But it didn't stop there.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The secret weapon:&lt;/strong&gt; I asked Claude Code to fetch and read the official disability regulations directly from the government website - the complete guidelines on how bodily impairments are assessed and calculated. With both the medical evidence AND the legal criteria in context, Claude Code could build arguments that directly mapped specific diagnoses to specific regulation paragraphs. For example, it found that "unstable spinal segment" and "severe spinal stenosis" each qualify as separate impairments that should be added together - something the commission had overlooked.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Version 1 → Version 11&lt;/strong&gt;: Each iteration got better:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;v1: Basic structure, main arguments&lt;/li&gt;
&lt;li&gt;v3: Added specific medical evidence with dates&lt;/li&gt;
&lt;li&gt;v5: Referenced disability regulations and legal basis&lt;/li&gt;
&lt;li&gt;v9: Incorporated new January 2026 findings&lt;/li&gt;
&lt;li&gt;v10: Added disability calculation showing 50%+ should be recognized&lt;/li&gt;
&lt;li&gt;v11: Final polish, comprehensive evidence list&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The final appeal grew from rough notes to a &lt;strong&gt;230-line legal document&lt;/strong&gt; with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;7 major sections with subsections&lt;/li&gt;
&lt;li&gt;30+ specific medical citations with dates&lt;/li&gt;
&lt;li&gt;Legal references to disability insurance law and internal guidelines&lt;/li&gt;
&lt;li&gt;Calculations showing multiple vertebral segments = higher disability %&lt;/li&gt;
&lt;li&gt;Request for home visit to verify living conditions&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Technical Magic: What Claude Code Actually Did
&lt;/h2&gt;

&lt;p&gt;Claude Code isn't just generating text. It's:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reading and cross-referencing documents:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"The MRI from November 2000 shows NO pathological changes...
If this were congenital, changes would be visible in 2000."
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Understanding medical terminology:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"CT scan confirms: 'Fresh osteoporotic fracture of
L4 vertebral body involving anterior and partially middle column.'"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Applying legal frameworks:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"Per disability guidelines Chapter VIII: 'When multiple segments
are affected, add 10% for each additional segment beyond
the first 30%.' L2 + L3 + L4 = 30% + 10% + 10% = 50%"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Finding contradictions:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"The commission's own expert opinion in Section 6 states:
'unstable segment L3-L4' - yet this was NOT considered
in the disability calculation!"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Document Pipeline
&lt;/h2&gt;

&lt;p&gt;Text file → Review → Iterate → Final &lt;code&gt;.docx&lt;/code&gt; and &lt;code&gt;.pdf&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;appeal-drafts/
├── appeal_v01.txt    # First draft
├── appeal_v05.txt    # Major revision
├── appeal_v09.txt    # With new evidence
├── appeal_v11.txt    # Final text
├── appeal_v11.docx   # Formatted Word doc
└── appeal_v11.pdf    # Print-ready PDF
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For the final step, I used Claude Code's &lt;strong&gt;docx skill&lt;/strong&gt; - a built-in capability that converts text documents into properly formatted Word files. One command, and the plain text appeal became a professional document with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Correct headers and formal structure&lt;/li&gt;
&lt;li&gt;Proper spacing and margins for official submissions&lt;/li&gt;
&lt;li&gt;Automatic PDF generation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No manual formatting in Word. No copy-paste headaches. The skill handled everything, producing government-ready documents directly from the terminal.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Learnings
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. AI is a multiplier, not a replacement&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I still needed to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Scan and organize documents&lt;/li&gt;
&lt;li&gt;Provide context and direction&lt;/li&gt;
&lt;li&gt;Verify every fact and citation&lt;/li&gt;
&lt;li&gt;Make judgment calls on arguments&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Claude Code amplified my efforts - turning hours of work into minutes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Structure matters&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;CLAUDE.md&lt;/code&gt; file was crucial. Clear project context meant better outputs from the first prompt.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Iteration is natural&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Don't expect perfection on v1. The v1→v11 journey wasn't failure - it was refinement. Each version incorporated new information, better arguments, and clearer language.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Domain knowledge can be learned&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Neither Claude Code nor I are lawyers or medical professionals. But by reading the regulations, understanding the criteria, and carefully citing evidence, we built a comprehensive legal argument.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Unexpected Outcome
&lt;/h2&gt;

&lt;p&gt;Using a programming tool for a legal appeal sounds absurd. But Claude Code's strengths translate perfectly:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Coding Task&lt;/th&gt;
&lt;th&gt;Legal Appeal Task&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Reading codebase&lt;/td&gt;
&lt;td&gt;Reading medical records&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Understanding APIs&lt;/td&gt;
&lt;td&gt;Understanding regulations&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Debugging errors&lt;/td&gt;
&lt;td&gt;Finding contradictions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Refactoring code&lt;/td&gt;
&lt;td&gt;Refining arguments&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Writing documentation&lt;/td&gt;
&lt;td&gt;Writing formal appeals&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  What Happens Next
&lt;/h2&gt;

&lt;p&gt;The appeal is submitted. We wait for the second-level commission's decision.&lt;/p&gt;

&lt;p&gt;But regardless of outcome, this experience taught me that AI tools aren't limited to their intended domains. A CLI built for &lt;code&gt;git commit&lt;/code&gt; and &lt;code&gt;npm install&lt;/code&gt; became the backbone of a deeply human fight for my mother's dignity and care.&lt;/p&gt;

&lt;p&gt;Sometimes the best tool for the job is the one you're already comfortable with.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Have you used AI tools for unexpected tasks? I'd love to hear about creative applications in the comments.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Technical note: The OCR script uses Google's Gemini with "thinking mode" for better accuracy on handwritten and faded documents (Claude Code has OCR too, but Gemini performed better on difficult scans). Claude Code handled document analysis, cross-referencing, fetching and parsing official regulations from government websites, iterative drafting, and final document conversion to DOCX/PDF via the built-in docx skill.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>claudecode</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Claude.ai Has Built-In Superpowers (And You Probably Didn't Know)</title>
      <dc:creator>Nunc</dc:creator>
      <pubDate>Mon, 27 Oct 2025 19:03:40 +0000</pubDate>
      <link>https://dev.to/nunc/claudeai-has-built-in-superpowers-and-you-probably-didnt-know-1haa</link>
      <guid>https://dev.to/nunc/claudeai-has-built-in-superpowers-and-you-probably-didnt-know-1haa</guid>
      <description>&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;: Claude.ai comes with 5 hidden "skills" that let it create Word docs, PowerPoint slides, Excel spreadsheets, and manipulate PDFs. Here's what Claude can actually do for you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wait, Claude Has Skills?
&lt;/h2&gt;

&lt;p&gt;Yeah! If you're using Claude.ai (the web or desktop version), you might've noticed it can do some pretty fancy document work. That's because Claude has these built-in "skills" - basically specialized knowledge for working with office documents.&lt;/p&gt;

&lt;p&gt;Most people just use Claude for chat and coding. But if you know how to ask, Claude can literally create a formatted Excel spreadsheet with formulas, build a PowerPoint deck, or edit a Word doc with tracked changes.&lt;/p&gt;

&lt;p&gt;Let me show you what's under the hood.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 5 Built-In Skills
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. DOCX Skill - Word Document Master
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;What it does:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creates professional Word documents from scratch&lt;/li&gt;
&lt;li&gt;Edits existing docs&lt;/li&gt;
&lt;li&gt;Handles tracked changes (redlining)&lt;/li&gt;
&lt;li&gt;Adds comments&lt;/li&gt;
&lt;li&gt;Preserves formatting&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Real-world uses:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You: "Create a business proposal document with sections for Executive Summary, Problem Statement, and Solution"

Claude: *generates a properly formatted .docx with headings, formatting, and structure*
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Pro tip:&lt;/strong&gt; If you need Claude to edit someone else's document (like legal or business docs), ask for "tracked changes" - Claude will mark every edit so reviewers can see what changed.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. PPTX Skill - Presentation Builder
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;What it does:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creates PowerPoint presentations&lt;/li&gt;
&lt;li&gt;Edits existing slides&lt;/li&gt;
&lt;li&gt;Works with layouts and templates&lt;/li&gt;
&lt;li&gt;Adds speaker notes&lt;/li&gt;
&lt;li&gt;Handles comments&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Real-world uses:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You: "Create a 5-slide pitch deck about our new product"

Claude: *builds a presentation with title slide, problem, solution, market, and call-to-action slides*
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Cool feature:&lt;/strong&gt; Claude can even work from templates - give it your company's branded PowerPoint template, and it'll create slides matching your style.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. XLSX Skill - Spreadsheet Wizard
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;What it does:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creates Excel files with formulas (not just data!)&lt;/li&gt;
&lt;li&gt;Formats cells (colors, fonts, number formats)&lt;/li&gt;
&lt;li&gt;Builds financial models&lt;/li&gt;
&lt;li&gt;Analyzes existing spreadsheets&lt;/li&gt;
&lt;li&gt;Calculates everything properly&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Real-world uses:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You: "Create a monthly budget tracker with categories for rent, food, utilities, and entertainment. Add formulas to calculate totals."

Claude: *generates an Excel file with proper formulas, formatting, and even color-coding*
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Key point:&lt;/strong&gt; Claude uses ACTUAL Excel formulas (like &lt;code&gt;=SUM(A1:A10)&lt;/code&gt;), not hardcoded values. Your spreadsheet will recalculate if you change inputs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Finance nerds:&lt;/strong&gt; Claude follows financial modeling standards:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Blue text = inputs&lt;/li&gt;
&lt;li&gt;Black text = formulas&lt;/li&gt;
&lt;li&gt;Green text = links from other sheets&lt;/li&gt;
&lt;li&gt;Red text = external links&lt;/li&gt;
&lt;li&gt;Yellow background = key assumptions&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. PDF Skill - PDF Surgeon
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;What it does:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Extracts text and tables from PDFs&lt;/li&gt;
&lt;li&gt;Merges multiple PDFs&lt;/li&gt;
&lt;li&gt;Splits PDFs into separate pages&lt;/li&gt;
&lt;li&gt;Creates new PDFs&lt;/li&gt;
&lt;li&gt;Fills PDF forms&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Real-world uses:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You: "Extract all the tables from this financial report PDF"

Claude: *pulls out tables as structured data you can work with*
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Handy trick:&lt;/strong&gt; Need to combine 5 different PDFs into one? Or split a 50-page PDF into individual files? Claude's got you.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Product Self-Knowledge Skill
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;What it does:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Answers questions about Claude products (API, Claude.ai, Claude Code)&lt;/li&gt;
&lt;li&gt;Provides accurate documentation links&lt;/li&gt;
&lt;li&gt;Distinguishes between different Claude products&lt;/li&gt;
&lt;li&gt;Prevents hallucinations about capabilities&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Real-world uses:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You: "Can Claude.ai access the internet?"

Claude: *gives accurate answer with source documentation link*
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why this matters:&lt;/strong&gt; This skill helps Claude give you accurate info about what it can and can't do, rather than making stuff up.&lt;/p&gt;

&lt;h2&gt;
  
  
  How To Use These Skills
&lt;/h2&gt;

&lt;p&gt;Here's the thing - &lt;strong&gt;you don't need to do anything special&lt;/strong&gt;. Just ask Claude naturally:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Examples that work:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"Create a Word document with..."
"Build me an Excel budget tracker..."
"Make a PowerPoint about..."
"Extract text from this PDF..."
"Merge these 3 PDFs together..."
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Claude will automatically activate the right skill for the job.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Claude Actually Does Behind The Scenes
&lt;/h2&gt;

&lt;p&gt;When you ask for a Word doc, Claude:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Uses a library called &lt;code&gt;docx-js&lt;/code&gt; to build the document structure&lt;/li&gt;
&lt;li&gt;Adds your content with proper formatting&lt;/li&gt;
&lt;li&gt;Exports as a real .docx file&lt;/li&gt;
&lt;li&gt;Gives you a download&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For Excel, Claude:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Uses &lt;code&gt;openpyxl&lt;/code&gt; (Python library)&lt;/li&gt;
&lt;li&gt;Writes actual Excel formulas (not calculated values)&lt;/li&gt;
&lt;li&gt;Applies formatting and colors&lt;/li&gt;
&lt;li&gt;Recalculates everything to make sure formulas work&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Pretty neat, right?&lt;/p&gt;

&lt;h2&gt;
  
  
  Real Examples I've Seen People Use
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Business use:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"Create a project status report with RAG status indicators"&lt;/li&gt;
&lt;li&gt;"Build a quarterly budget spreadsheet with formulas"&lt;/li&gt;
&lt;li&gt;"Make a 10-slide training deck about security policies"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Personal use:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"Create a budget tracker for my expenses"&lt;/li&gt;
&lt;li&gt;"Build a presentation about my vacation photos"&lt;/li&gt;
&lt;li&gt;"Extract text from these scanned receipts"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Academic use:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"Create a formatted research paper template"&lt;/li&gt;
&lt;li&gt;"Build a data analysis spreadsheet with charts"&lt;/li&gt;
&lt;li&gt;"Merge all my assignment PDFs into one document"&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Limitations To Know
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What Claude CAN'T do:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Open existing files you haven't uploaded&lt;/li&gt;
&lt;li&gt;Edit files on your computer directly&lt;/li&gt;
&lt;li&gt;Access your Google Drive or OneDrive&lt;/li&gt;
&lt;li&gt;Send files to other services&lt;/li&gt;
&lt;li&gt;Create files larger than a few MB&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;What Claude CAN do:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Work with files you upload in the chat&lt;/li&gt;
&lt;li&gt;Create new files from scratch&lt;/li&gt;
&lt;li&gt;Process and analyze documents&lt;/li&gt;
&lt;li&gt;Generate properly formatted office documents&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Pro Tips
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Tip 1: Be Specific About Formatting
&lt;/h3&gt;

&lt;p&gt;Instead of: "Create a spreadsheet"&lt;/p&gt;

&lt;p&gt;Try: "Create an Excel spreadsheet with blue headers, bold column names, and formulas to calculate totals"&lt;/p&gt;

&lt;h3&gt;
  
  
  Tip 2: Ask For Examples First
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You: "Show me what the Excel file will look like before creating it"

Claude: *describes structure, then creates it*
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Tip 3: Iterate
&lt;/h3&gt;

&lt;p&gt;Don't expect perfection on first try. You can say:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"Add a new column for..."&lt;/li&gt;
&lt;li&gt;"Change the formatting to..."&lt;/li&gt;
&lt;li&gt;"Add speaker notes to each slide..."&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Tip 4: Upload Templates
&lt;/h3&gt;

&lt;p&gt;Have a company template? Upload it and say:&lt;br&gt;
"Use this template and create a presentation about [topic]"&lt;/p&gt;
&lt;h2&gt;
  
  
  How This Compares To Other Tools
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;vs Microsoft Copilot:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Claude: Better at understanding complex requests&lt;/li&gt;
&lt;li&gt;Copilot: Better at integrating with your existing Office files&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;vs ChatGPT:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Claude: Built-in office document skills&lt;/li&gt;
&lt;li&gt;ChatGPT: Requires plugins or third-party tools&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;vs Google Docs AI:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Claude: Creates downloadable files&lt;/li&gt;
&lt;li&gt;Google Docs: Works directly in your docs&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Why This Matters
&lt;/h2&gt;

&lt;p&gt;This isn't just "cool AI tricks" - it's genuinely useful:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scenario 1: Quick Mockups&lt;/strong&gt;&lt;br&gt;
Need a financial model for a pitch tomorrow? Claude can build the skeleton in minutes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scenario 2: Document Processing&lt;/strong&gt;&lt;br&gt;
Got 50 PDFs to extract data from? Claude can automate it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scenario 3: Template Creation&lt;/strong&gt;&lt;br&gt;
Need a standard report format? Create it once with Claude, then reuse.&lt;/p&gt;
&lt;h2&gt;
  
  
  Try It Now
&lt;/h2&gt;

&lt;p&gt;Pick one and paste it into Claude.ai:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Create a personal budget Excel spreadsheet with:
- Monthly income section
- Expense categories (rent, food, transport, entertainment)
- Formulas to calculate totals and remaining balance
- Color coding (expenses in red, income in green)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Create a 3-slide PowerPoint about time management with:
- Slide 1: Title "Productivity Tips"
- Slide 2: 5 bullet points with tips
- Slide 3: Call to action
- Add speaker notes to each slide
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Bottom Line
&lt;/h2&gt;

&lt;p&gt;Claude.ai is more than a chatbot - it's a document creation powerhouse. These 5 built-in skills mean you can go from "I need a spreadsheet" to having an actual, working Excel file in minutes.&lt;/p&gt;

&lt;p&gt;No plugins. No third-party tools. No copy-paste. Just ask.&lt;/p&gt;

&lt;p&gt;Next time you're about to spend 30 minutes formatting a Word doc or building a spreadsheet, try asking Claude first. You might be surprised.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Have you used Claude to create documents? What worked well? What didn't? Drop your experiences in the comments!&lt;/strong&gt; 💬&lt;/p&gt;

&lt;p&gt;&lt;em&gt;P.S. - These skills are built into Claude.ai and Claude for Desktop. If you're using the API, you'd need to implement document handling yourself.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>claude</category>
      <category>productivity</category>
      <category>tools</category>
    </item>
    <item>
      <title>Claude Code Skills vs Subagents - When to Use What?</title>
      <dc:creator>Nunc</dc:creator>
      <pubDate>Mon, 27 Oct 2025 19:03:26 +0000</pubDate>
      <link>https://dev.to/nunc/claude-code-skills-vs-subagents-when-to-use-what-4d12</link>
      <guid>https://dev.to/nunc/claude-code-skills-vs-subagents-when-to-use-what-4d12</guid>
      <description>&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;: Skills are like recipes, subagents are like specialized coworkers. Both extend Claude Code, but knowing when to use which saves you a ton of headache.&lt;/p&gt;

&lt;p&gt;So I was building a document reader for Claude Code (to process Word docs, PDFs, Excel files from support tickets), and I hit this question: "Should this be a &lt;strong&gt;skill&lt;/strong&gt; or a &lt;strong&gt;subagent&lt;/strong&gt;?"&lt;/p&gt;

&lt;p&gt;Turns out, this is a pretty common confusion. Let me save you the research time.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Quick Version
&lt;/h2&gt;

&lt;p&gt;Here's the cheat sheet:&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;Skills&lt;/th&gt;
&lt;th&gt;Subagents&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;What it is&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Instructions that extend Claude's knowledge&lt;/td&gt;
&lt;td&gt;A separate AI assistant with its own context&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;When Claude uses it&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Automatically when relevant&lt;/td&gt;
&lt;td&gt;Delegated for complex workflows&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Best for&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Utility functions, recipes, how-tos&lt;/td&gt;
&lt;td&gt;Multi-step analysis, code review, research&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Context&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Shares your main chat context&lt;/td&gt;
&lt;td&gt;Gets its own isolated context window&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Think of it this way:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Skill&lt;/strong&gt; = giving Claude a cookbook&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Subagent&lt;/strong&gt; = hiring a sous chef&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Skills: The Recipe Approach
&lt;/h2&gt;

&lt;p&gt;Skills are markdown files with instructions. Claude reads them when it needs help with something specific.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example structure:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;~/.claude/skills/document-reader/
├── SKILL.md          (main instructions)
├── examples.md       (usage examples)
└── scripts/
    └── converter.py  (optional helper script)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;When to use skills:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Converting files (PDF → text, DOCX → text)&lt;/li&gt;
&lt;li&gt;Template generation&lt;/li&gt;
&lt;li&gt;Style guides for code/writing&lt;/li&gt;
&lt;li&gt;Domain knowledge (business rules, API docs)&lt;/li&gt;
&lt;li&gt;Quick utility functions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Why skills are great:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;⚡ Fast - Claude just reads instructions&lt;/li&gt;
&lt;li&gt;🔄 Reusable - any conversation can use them&lt;/li&gt;
&lt;li&gt;🪶 Lightweight - no separate AI needed&lt;/li&gt;
&lt;li&gt;🤖 Auto-activated - Claude decides when to use them&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Example skill description:&lt;/strong&gt;&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="nn"&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;document-reader&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Converts document files (.pdf, .docx, .xlsx) to text. Use when reading document attachments, analyzing files from tickets, or extracting content from PDFs and spreadsheets.&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice: it tells Claude &lt;strong&gt;what&lt;/strong&gt; it does and &lt;strong&gt;when&lt;/strong&gt; to use it. That's key.&lt;/p&gt;

&lt;h2&gt;
  
  
  Subagents: The Specialized Coworker
&lt;/h2&gt;

&lt;p&gt;Subagents are like delegating work to a specialist. They get their own context window and run independently.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When to use subagents:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Code review workflows&lt;/li&gt;
&lt;li&gt;Multi-file analysis&lt;/li&gt;
&lt;li&gt;Research tasks that need deep investigation&lt;/li&gt;
&lt;li&gt;Tasks that would clutter your main conversation&lt;/li&gt;
&lt;li&gt;When you need focused, dedicated reasoning&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Why subagents rock:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🧠 Deep focus - dedicated context for complex tasks&lt;/li&gt;
&lt;li&gt;🔍 Multi-step reasoning - can work through problems systematically&lt;/li&gt;
&lt;li&gt;🎯 Specialized - custom prompts for specific workflows&lt;/li&gt;
&lt;li&gt;🧹 Clean separation - doesn't pollute main chat&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Example subagent:&lt;/strong&gt;&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="nn"&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;code-reviewer&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Reviews code for best practices and security issues. Use when reviewing PRs or analyzing code quality.&lt;/span&gt;
&lt;span class="na"&gt;tools&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Read, Grep, Glob&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

&lt;span class="s"&gt;You are a specialized code reviewer...&lt;/span&gt;
&lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;detailed instructions for review process&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Real Example: Document Reader
&lt;/h2&gt;

&lt;p&gt;Here's how I decided for my document reader:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The task:&lt;/strong&gt; Read PDF/DOCX/XLSX files from support tickets&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;My thought process:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Is this complex multi-step reasoning? &lt;strong&gt;No&lt;/strong&gt; - just file conversion&lt;/li&gt;
&lt;li&gt;Does it need its own context? &lt;strong&gt;No&lt;/strong&gt; - simple input/output&lt;/li&gt;
&lt;li&gt;Is it a utility function? &lt;strong&gt;Yes&lt;/strong&gt; - convert file to text&lt;/li&gt;
&lt;li&gt;Will other agents need this? &lt;strong&gt;Yes&lt;/strong&gt; - zahtevki-researcher needs it&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Decision: Make it a skill ✅&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If I needed to &lt;em&gt;analyze&lt;/em&gt; documents across multiple tickets, &lt;em&gt;compare&lt;/em&gt; them, and &lt;em&gt;generate reports&lt;/em&gt;? That would be a subagent.&lt;/p&gt;

&lt;h2&gt;
  
  
  How They Work Together
&lt;/h2&gt;

&lt;p&gt;Here's the cool part - they complement each other:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;zahtevki-researcher (subagent)
  ↓
Downloads ticket attachment.docx
  ↓
Invokes document-reader (skill)
  ↓
Converts to text
  ↓
Analyzes content
  ↓
Returns findings
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The subagent handles the complex workflow, the skill handles the utility function.&lt;/p&gt;

&lt;h2&gt;
  
  
  Decision Tree
&lt;/h2&gt;

&lt;p&gt;Use this when you're stuck:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is it a utility/conversion/template?&lt;/strong&gt; → Skill&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does it need multiple steps of reasoning?&lt;/strong&gt; → Subagent&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Will it be reused across different tasks?&lt;/strong&gt; → Skill&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is it a complex workflow with validation loops?&lt;/strong&gt; → Subagent&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is it knowledge Claude doesn't have?&lt;/strong&gt; → Skill&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does it need to coordinate multiple operations?&lt;/strong&gt; → Subagent&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick Tips
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;For Skills:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Keep SKILL.md under 500 lines&lt;/li&gt;
&lt;li&gt;Use progressive disclosure (main file → reference files)&lt;/li&gt;
&lt;li&gt;Write descriptions in third person&lt;/li&gt;
&lt;li&gt;Include trigger words (when to use it)&lt;/li&gt;
&lt;li&gt;Make them discoverable&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;For Subagents:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Write detailed system prompts&lt;/li&gt;
&lt;li&gt;Define clear responsibilities (single focus)&lt;/li&gt;
&lt;li&gt;Limit tool access to what's needed&lt;/li&gt;
&lt;li&gt;Test that they activate correctly&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What I Learned
&lt;/h2&gt;

&lt;p&gt;After building both, here's my take:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Start with a skill&lt;/strong&gt; unless you specifically need subagent features. Skills are simpler, faster, and easier to maintain.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Upgrade to subagent&lt;/strong&gt; when you're doing actual &lt;em&gt;workflows&lt;/em&gt; - things with multiple steps, decision points, validation loops.&lt;/p&gt;

&lt;p&gt;My document reader? Perfect as a skill. It's fast, reusable, and other agents can invoke it seamlessly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try It Yourself
&lt;/h2&gt;

&lt;p&gt;Want to build your own? Here's a 5-minute starter:&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;# Create a skill directory&lt;/span&gt;
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; ~/.claude/skills/my-skill

&lt;span class="c"&gt;# Create SKILL.md&lt;/span&gt;
&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; ~/.claude/skills/my-skill/SKILL.md &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;'
---
name: my-skill
description: What it does and when to use it
---

# My Skill

Instructions go here...
&lt;/span&gt;&lt;span class="no"&gt;EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next time you chat with Claude, it'll automatically discover and use your skill!&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;What are you building with Claude Code? Skills or subagents? Share in the comments - I'd love to hear what you're working on!&lt;/strong&gt; 🚀&lt;/p&gt;

&lt;p&gt;&lt;em&gt;P.S. - If you found this helpful, I'm documenting my whole journey building skills for an insurance system. Follow along if you're into that sort of thing!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>claude</category>
      <category>productivity</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How I Built Agent Skills for Claude Code</title>
      <dc:creator>Nunc</dc:creator>
      <pubDate>Tue, 21 Oct 2025 12:05:19 +0000</pubDate>
      <link>https://dev.to/nunc/how-i-built-agent-skills-for-claude-code-oj4</link>
      <guid>https://dev.to/nunc/how-i-built-agent-skills-for-claude-code-oj4</guid>
      <description>&lt;p&gt;&lt;strong&gt;How I stopped re-explaining my legacy database every single conversation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;So I was working with this gnarly Oracle database - 1,048 packages, 20,913 stored procedures, Slovenian terminology, old-school SQL syntax from the 90s. You know the type.&lt;/p&gt;

&lt;p&gt;Every time I asked Claude for help, I'd spend the first 10 minutes explaining:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"No, use WHERE joins, not ANSI JOIN"&lt;/li&gt;
&lt;li&gt;"That's Slovenian for 'claim file'"&lt;/li&gt;
&lt;li&gt;"We always validate extraction quality"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It got old. Fast.&lt;/p&gt;

&lt;p&gt;Then I discovered Agent Skills. Now Claude just... knows. It's like I taught it once, and it remembers forever.&lt;/p&gt;

&lt;p&gt;Let me show you how I did it, because honestly, it's easier than you think.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Even Are Agent Skills?
&lt;/h2&gt;

&lt;p&gt;Think of them as plugins for Claude. Little knowledge modules that Claude loads automatically when it needs them.&lt;/p&gt;

&lt;p&gt;You write a markdown file saying "Here's how to work with my database" or "Here's how our API works" - and Claude references it whenever relevant. No more repetitive explanations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The magic part&lt;/strong&gt;: You don't manually activate skills. Claude reads the descriptions and figures out which ones to use. It's actually pretty smart about it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Absolute Minimum You Need
&lt;/h2&gt;

&lt;p&gt;One file. That's it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;~/.claude/skills/my-thing/
└── SKILL.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's a complete working skill:&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="nn"&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;pdf-tools&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Extract text from PDFs using pdfplumber. Use when working with PDF files.&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# PDF Tools&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





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

&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;pdfplumber&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;file.pdf&lt;/span&gt;&lt;span class="sh"&gt;"&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;pdf&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pages&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;extract_text&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;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Done. You now have a skill. Seriously.&lt;/p&gt;

&lt;h2&gt;
  
  
  The One Rule That Matters
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Keep it short.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Claude's context window is shared between your conversation, the code, other skills, and everything else. Don't waste tokens.&lt;/p&gt;

&lt;p&gt;Here's what I mean:&lt;/p&gt;

&lt;h3&gt;
  
  
  ❌ This wastes everyone's time
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## Extract PDF text&lt;/span&gt;

PDF stands for Portable Document Format. It's a file format developed by Adobe in 1992 for presenting documents. PDFs can contain text, images, forms, and more. To extract text from a PDF, you'll need to use a specialized library. There are many options available in Python, such as PyPDF2, pdfplumber, and PyMuPDF. We recommend pdfplumber because it's actively maintained and handles most edge cases well. First, you'll need to install it using pip...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ✅ This is what Claude actually needs
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## Extract PDF text&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pdfplumber&lt;/span&gt;
&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;pdfplumber&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;file.pdf&lt;/span&gt;&lt;span class="sh"&gt;"&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;pdf&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pages&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;extract_text&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Claude already knows what PDFs are. Show the code, move on.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Target: Keep your main SKILL.md file under 500 lines.&lt;/strong&gt; If you need more, split it into reference files (I'll show you how in a sec).&lt;/p&gt;

&lt;h2&gt;
  
  
  Writing Descriptions That Actually Work
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;description&lt;/code&gt; in your YAML frontmatter is critical. It's how Claude decides whether to load your skill.&lt;/p&gt;

&lt;p&gt;The formula that works:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What it does + When to use it + Trigger words&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Examples that work
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Extract text from PDFs using pdfplumber. Use when working with PDF files, forms, or document extraction.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Connect to Oracle database, extract PL/SQL packages with old-style SQL syntax. Use for Oracle database operations or PL/SQL code extraction.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Analyze Excel spreadsheets, create pivot tables. Use when working with .xlsx files or tabular data.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  What doesn't work
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Helps with files&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Does database stuff&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Utility functions&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Too vague. Claude won't know when to use it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pro tip&lt;/strong&gt;: Always write in third person ("Extracts text from PDFs" not "I can extract text"). Claude's system prompt uses third person, so first/second person confuses things.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Secret: Progressive Disclosure
&lt;/h2&gt;

&lt;p&gt;This is the pattern that lets your skills scale without bloating the context window.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The idea&lt;/strong&gt;: Your SKILL.md is like a table of contents. Point to details, don't include everything upfront.&lt;/p&gt;

&lt;p&gt;Here's how it works:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Claude loads all skill descriptions at startup (just names + descriptions)&lt;/li&gt;
&lt;li&gt;When triggered, Claude loads your SKILL.md&lt;/li&gt;
&lt;li&gt;As needed, Claude reads specific reference files&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Example structure
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# API Client&lt;/span&gt;

&lt;span class="gu"&gt;## Quick Start&lt;/span&gt;
[Basic code example here]

&lt;span class="gu"&gt;## Advanced&lt;/span&gt;

Need authentication? See &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;AUTH.md&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;AUTH.md&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
Rate limiting? See &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;LIMITS.md&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;LIMITS.md&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
Error handling? See &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;ERRORS.md&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;ERRORS.md&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Claude only reads AUTH.md when someone asks about authentication. Saves tons of context.&lt;/p&gt;

&lt;h3&gt;
  
  
  Keep it one level deep though
&lt;/h3&gt;

&lt;p&gt;❌ Don't do this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SKILL.md → advanced.md → details.md → actual_info.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;✅ Do this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SKILL.md → auth.md, limits.md, errors.md, examples.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Claude sometimes only partially reads nested files, so keep references direct from SKILL.md.&lt;/p&gt;

&lt;h3&gt;
  
  
  Table of Contents for long files
&lt;/h3&gt;

&lt;p&gt;If a reference file gets over 100 lines, add a ToC at the top:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# API Reference&lt;/span&gt;

&lt;span class="gu"&gt;## Contents&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;Authentication&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;#authentication&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;Endpoints&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;#endpoints&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;Error Codes&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;#error-codes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;
---
&lt;/span&gt;
&lt;span class="gu"&gt;## Authentication&lt;/span&gt;
[...]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This helps Claude navigate even when it only partially reads the file.&lt;/p&gt;

&lt;h2&gt;
  
  
  Real Example: My Oracle Nightmare (Now Solved)
&lt;/h2&gt;

&lt;p&gt;Let me show you the actual skill I built. It started as a mess and ended up at 100% compliance with Anthropic's best practices.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Problem
&lt;/h3&gt;

&lt;p&gt;I work with this insurance application database:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;1,048 PL/SQL packages&lt;/li&gt;
&lt;li&gt;20,913 procedures (yes, really)&lt;/li&gt;
&lt;li&gt;All the business terms in Slovenian&lt;/li&gt;
&lt;li&gt;SQL syntax from 1995 (WHERE clause joins only, no ANSI)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'd have the same conversation every day:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"Use WHERE joins, not INNER JOIN"&lt;/li&gt;
&lt;li&gt;"That column is 'skondi_spis' which means claim file"&lt;/li&gt;
&lt;li&gt;"Check the line count after extraction to validate"&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The Solution: Two Skills, Not One
&lt;/h3&gt;

&lt;p&gt;I almost made one giant skill with everything. Thank god I didn't.&lt;/p&gt;

&lt;p&gt;Instead:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;db-toolkit&lt;/strong&gt; - How to connect, extract, query (technical stuff)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;business-domain&lt;/strong&gt; - What the tables mean, business processes (domain knowledge)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Why separate?&lt;/strong&gt; They change at different rates. Database operations don't change much. Business knowledge updates constantly. Sometimes I only need one.&lt;/p&gt;

&lt;h3&gt;
  
  
  Here's the db-toolkit structure
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;~/.claude/skills/db-toolkit/
├── SKILL.md (687 lines - yeah, over 500, but it's worth it)
├── reference.md (API docs for all methods)
├── usage-examples.md (10+ real scenarios)
├── sql-syntax-guide.md (old-style SQL examples)
├── troubleshooting.md (common errors)
└── scripts/
    └── oracle_toolkit_standalone.py (the actual code)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  What made it actually work
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1. Everything's embedded&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No external dependencies. The Python code lives in &lt;code&gt;scripts/&lt;/code&gt; inside the skill:&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;pathlib&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;

&lt;span class="n"&gt;skill_dir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;home&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;.claude&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;skills&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;db-toolkit&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;skill_dir&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;scripts&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;oracle_toolkit_standalone&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;OracleToolkit&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Skill works anywhere.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Copy-paste checklists&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Best thing I added. For complex workflows, give Claude a checklist to track:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;Copy this checklist:

Task Progress:
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Connect to database
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Extract package body
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Validate extraction (check line count)
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Copy to working directory
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Make changes
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Run tests
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Claude checks items off as it works. I can see progress. Users love this.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Validate everything immediately&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Every operation gets validated right away with specific help:&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;pkg&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;toolkit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;extract_source&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_SCHEMA&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;PKG_EXAMPLE&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;PACKAGE BODY&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;pkg&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;success&lt;/span&gt;&lt;span class="sh"&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;❌ Failed:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pkg&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;message&lt;/span&gt;&lt;span class="sh"&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;🔄 Try these fixes:&lt;/span&gt;&lt;span class="sh"&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;  • Check package name spelling&lt;/span&gt;&lt;span class="sh"&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;  • Use &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;PACKAGE BODY&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt; not &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;PACKAGE&lt;/span&gt;&lt;span class="sh"&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;  • Verify schema owner is correct&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;

&lt;span class="c1"&gt;# Also validate quality
&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;pkg&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;line_count&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;10&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;⚠️  Suspiciously small extraction - double check&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;p&gt;No more mystery errors later.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Skills reference each other&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;db-toolkit mentions business-domain for business context.&lt;br&gt;
business-domain mentions db-toolkit for database operations.&lt;/p&gt;

&lt;p&gt;Claude figures out when it needs both.&lt;/p&gt;
&lt;h3&gt;
  
  
  Results
&lt;/h3&gt;

&lt;p&gt;After refining over a few weeks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ 100% compliance with Anthropic best practices&lt;/li&gt;
&lt;li&gt;✅ 85.7% test pass rate (12 out of 14 tests)&lt;/li&gt;
&lt;li&gt;✅ Saves me probably 10 hours a week&lt;/li&gt;
&lt;li&gt;✅ Works reliably across sessions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: My SKILL.md is 687 lines, which is over the recommended 500. But it's validated workflows with checklists that users copy directly. Worth the trade-off.&lt;/p&gt;
&lt;h2&gt;
  
  
  Patterns I Use All The Time
&lt;/h2&gt;
&lt;h3&gt;
  
  
  1. The Template Pattern
&lt;/h3&gt;

&lt;p&gt;When you need exact output format, put this in your SKILL.md:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example SKILL.md content:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## Report Format&lt;/span&gt;

ALWAYS use this structure:
&lt;span class="gh"&gt;# [Title]&lt;/span&gt;
&lt;span class="gu"&gt;## Summary&lt;/span&gt;
[One paragraph]

&lt;span class="gu"&gt;## Findings&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Finding 1
&lt;span class="p"&gt;-&lt;/span&gt; Finding 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For flexible stuff, say "adapt as needed" instead of "ALWAYS."&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Show Examples, Not Descriptions
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Example SKILL.md content:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## Commit Messages&lt;/span&gt;

&lt;span class="gs"&gt;**Example**&lt;/span&gt;:
Input: "Added user auth with JWT"
Output:
feat(auth): implement JWT authentication

Add login endpoint and token validation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One example beats ten paragraphs.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Guide Through Decisions
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Example SKILL.md content:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## What to do&lt;/span&gt;

Determine your situation:

&lt;span class="gs"&gt;**Creating new document?**&lt;/span&gt; → Use Creation Workflow below
&lt;span class="gs"&gt;**Editing existing?**&lt;/span&gt; → Use Editing Workflow below

&lt;span class="gu"&gt;### Creation Workflow&lt;/span&gt;
[steps...]

&lt;span class="gu"&gt;### Editing Workflow&lt;/span&gt;
[steps...]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How I Actually Built It (Not How You'd Think)
&lt;/h2&gt;

&lt;p&gt;I didn't sit down and write a massive spec. Here's what actually worked:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Started with the pain points
&lt;/h3&gt;

&lt;p&gt;Used Claude for a week without a skill. Noted every time I had to repeat myself:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Explained old-style SQL 5 times → added syntax guide&lt;/li&gt;
&lt;li&gt;Kept saying "validate extraction" → added validation loops&lt;/li&gt;
&lt;li&gt;Explained Slovenian terms constantly → added glossary&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Built the skill from actual problems, not imagined ones.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Wrote tests first
&lt;/h3&gt;

&lt;p&gt;Created 3 simple test scenarios:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Test 1: "Extract package PKG_EXAMPLE" → should connect and extract
Test 2: "Show me tables for this module" → should list relevant tables
Test 3: "Fix this SQL join" → should suggest old-style syntax
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then wrote just enough skill content to pass those tests.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Observed what Claude actually read
&lt;/h3&gt;

&lt;p&gt;Watched which files Claude opened:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Went to sql-syntax-guide.md often → made it clearer&lt;/li&gt;
&lt;li&gt;Rarely opened troubleshooting.md → moved common stuff to SKILL.md&lt;/li&gt;
&lt;li&gt;Skipped parts of examples.md → added ToC for faster navigation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Adjusted based on behavior.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. The "3 times rule"
&lt;/h3&gt;

&lt;p&gt;If I explained something 3 times in conversations → it went in the skill.&lt;/p&gt;

&lt;p&gt;Example: Kept saying "use (+) for outer joins" → added to SQL guide with examples.&lt;/p&gt;

&lt;h2&gt;
  
  
  What NOT to Do (I learned the hard way)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ❌ Time-sensitive info
&lt;/h3&gt;

&lt;p&gt;Don't write:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;Before August 2025, use old API.
After August 2025, use new API.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Skills should be evergreen.&lt;/p&gt;

&lt;h3&gt;
  
  
  ❌ Windows paths
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Bad
&lt;/span&gt;&lt;span class="n"&gt;scripts&lt;/span&gt;\&lt;span class="n"&gt;helper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt;

&lt;span class="c1"&gt;# Good
&lt;/span&gt;&lt;span class="n"&gt;scripts&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;helper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Always forward slashes.&lt;/p&gt;

&lt;h3&gt;
  
  
  ❌ Offering too many options
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# Bad&lt;/span&gt;
You could use library A, B, C, D, E, F, or G...

&lt;span class="gh"&gt;# Good&lt;/span&gt;
Use pdfplumber for most cases.
Edge cases? See &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;alternatives.md&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;alternatives.md&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ❌ Mega-skills
&lt;/h3&gt;

&lt;p&gt;Don't make one skill for everything:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;database-and-api-and-deployment-and-monitoring/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make focused skills:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;database-toolkit/
api-client/
deployment/
monitoring/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Quick Start: Build Your First Skill Right Now
&lt;/h2&gt;

&lt;p&gt;Pick something you explain to Claude repeatedly. For me it was database stuff. For you maybe it's:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How your API works&lt;/li&gt;
&lt;li&gt;Your company's coding standards&lt;/li&gt;
&lt;li&gt;Common git workflows&lt;/li&gt;
&lt;li&gt;Specific library you use a lot&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  5-minute version
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; ~/.claude/skills/my-thing
&lt;span class="nb"&gt;cd&lt;/span&gt; ~/.claude/skills/my-thing
nano SKILL.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Write this:&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="nn"&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;my-thing&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;What it does&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;&lt;span class="s"&gt;. Use when [trigger words].&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

&lt;span class="c1"&gt;# My Thing&lt;/span&gt;

&lt;span class="c1"&gt;## Quick Start&lt;/span&gt;

&lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;One code example&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="c1"&gt;## Common Tasks&lt;/span&gt;

&lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;2-3 more examples&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save it. Ask Claude a question that should trigger it.&lt;/p&gt;

&lt;p&gt;That's it. You have a working skill.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Checklist (So You Know You're Done)
&lt;/h2&gt;

&lt;p&gt;Before you call a skill "done":&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Structure&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[ ] SKILL.md under 500 lines (or you have a good reason)&lt;/li&gt;
&lt;li&gt;[ ] Valid YAML with name and description&lt;/li&gt;
&lt;li&gt;[ ] If you have reference files, they link from SKILL.md (not nested deeper)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Description&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Third person ("Processes files" not "I process")&lt;/li&gt;
&lt;li&gt;[ ] Says what it does&lt;/li&gt;
&lt;li&gt;[ ] Says when to use it&lt;/li&gt;
&lt;li&gt;[ ] Under 1024 characters&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Content&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Assumes Claude is smart (no explanations of basic concepts)&lt;/li&gt;
&lt;li&gt;[ ] Consistent terms throughout&lt;/li&gt;
&lt;li&gt;[ ] No dates or version numbers that'll expire&lt;/li&gt;
&lt;li&gt;[ ] Forward slashes in paths&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Testing&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Tried it with real questions&lt;/li&gt;
&lt;li&gt;[ ] Claude activates it when it should&lt;/li&gt;
&lt;li&gt;[ ] Claude finds the right info&lt;/li&gt;
&lt;li&gt;[ ] At least 80% success rate&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What I Learned
&lt;/h2&gt;

&lt;p&gt;Building the db-toolkit skill changed how I work with Claude. Instead of fighting with it every conversation, it just knows my database quirks.&lt;/p&gt;

&lt;p&gt;The skill saves me probably 10 hours a week. No more:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Re-explaining SQL syntax&lt;/li&gt;
&lt;li&gt;Translating Slovenian terms&lt;/li&gt;
&lt;li&gt;Reminding it to validate extractions&lt;/li&gt;
&lt;li&gt;Describing table relationships&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It just works.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best part?&lt;/strong&gt; Skills improve with use. Each conversation shows you what's missing. Each addition makes the next session better.&lt;/p&gt;

&lt;p&gt;I started with a 100-line SKILL.md. Over 3 months of actual use, it grew to 3,100 lines across multiple files - but only because I found real gaps worth filling.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your Turn
&lt;/h2&gt;

&lt;p&gt;Start small. Don't try to document everything. Pick one thing you repeat constantly and build a skill for that.&lt;/p&gt;

&lt;p&gt;Maybe it's:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your database schema&lt;/li&gt;
&lt;li&gt;API endpoints you use&lt;/li&gt;
&lt;li&gt;Git workflow your team follows&lt;/li&gt;
&lt;li&gt;Library you use every project&lt;/li&gt;
&lt;li&gt;Testing patterns&lt;/li&gt;
&lt;li&gt;Deployment process&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Whatever it is, write a minimal SKILL.md. Use it for a week. See what's missing. Add that.&lt;/p&gt;

&lt;p&gt;In a month you'll wonder how you ever worked without it.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Questions? Built a skill and want to share? Drop a comment - I'm genuinely curious what you build.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>claude</category>
      <category>ai</category>
      <category>productivity</category>
      <category>development</category>
    </item>
  </channel>
</rss>
