<?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: yabbal</title>
    <description>The latest articles on DEV Community by yabbal (@yabbal).</description>
    <link>https://dev.to/yabbal</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F125737%2F4acce618-b6a1-4fd6-a990-fe27dde8024f.png</url>
      <title>DEV Community: yabbal</title>
      <link>https://dev.to/yabbal</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/yabbal"/>
    <language>en</language>
    <item>
      <title>I Reverse-Engineered an Undocumented API and Shipped 2 npm Packages in 4 Days — with Claude Code</title>
      <dc:creator>yabbal</dc:creator>
      <pubDate>Tue, 10 Mar 2026 19:56:15 +0000</pubDate>
      <link>https://dev.to/yabbal/i-reverse-engineered-an-undocumented-api-and-shipped-2-npm-packages-in-4-days-with-claude-code-5cm9</link>
      <guid>https://dev.to/yabbal/i-reverse-engineered-an-undocumented-api-and-shipped-2-npm-packages-in-4-days-with-claude-code-5cm9</guid>
      <description>&lt;p&gt;&lt;em&gt;A freelancer's frustration, an undocumented API, and an AI pair-programmer. Here's how it went.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The spark: a freelancer's itch
&lt;/h2&gt;

&lt;p&gt;I'm a developer, and like many freelancers in France, I use &lt;a href="https://www.tiime.fr/" rel="noopener noreferrer"&gt;Tiime&lt;/a&gt; for my accounting. Invoices, bank transactions, categorization — everything goes through their web UI.&lt;/p&gt;

&lt;p&gt;The problem? When you juggle multiple companies, you end up doing the same repetitive clicks every month. Checking uncategorized transactions, creating recurring invoices, auditing accounts... The kind of tasks that scream "automate me."&lt;/p&gt;

&lt;p&gt;Except Tiime has no public API. No documentation. No SDK. Nothing.&lt;/p&gt;

&lt;p&gt;So one Friday night, at 2:30 AM, I opened my terminal and typed:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Build me a CLI for Tiime. Scan the entire app and map out every REST API endpoint."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;My conversation partner? Claude Code. We didn't stop for 4 days.&lt;/p&gt;




&lt;h2&gt;
  
  
  Day 1 — Reverse-engineering the API
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Sniffing the network
&lt;/h3&gt;

&lt;p&gt;No Swagger, no docs — we had to intercept network requests straight from the frontend.&lt;/p&gt;

&lt;p&gt;I opened Chrome DevTools, logged into Tiime, and let Claude analyze everything going through the wire. Within hours, we had mapped &lt;strong&gt;40+ endpoints&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Auth&lt;/strong&gt;: Auth0 with a &lt;code&gt;password&lt;/code&gt; grant (not &lt;code&gt;password-realm&lt;/code&gt; — a subtle distinction that cost us time)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Custom headers&lt;/strong&gt;: &lt;code&gt;tiime-app: tiime&lt;/code&gt;, &lt;code&gt;tiime-app-version: 4.30.3&lt;/code&gt;, &lt;code&gt;tiime-app-platform: web&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pagination&lt;/strong&gt;: via the &lt;code&gt;Range: items=0-25&lt;/code&gt; header, with &lt;code&gt;206 Partial Content&lt;/code&gt; responses&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Content negotiation&lt;/strong&gt;: exotic &lt;code&gt;Accept&lt;/code&gt; headers like &lt;code&gt;application/vnd.tiime.bank_transactions.label_suggestions.v2+json&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No documentation gives you these details. You discover them one request at a time.&lt;/p&gt;

&lt;h3&gt;
  
  
  The SDK takes shape
&lt;/h3&gt;

&lt;p&gt;Once the API landscape was clear, I made a deliberate design choice: this project would be &lt;strong&gt;built for AI agents from the start&lt;/strong&gt;. The CLI wouldn't just be a terminal tool — it would be exposed to Claude Code via a Skill, enabling natural language queries against Tiime.&lt;/p&gt;

&lt;p&gt;That meant clean JSON output, atomic commands, and — most importantly — a reusable SDK separated from the CLI.&lt;/p&gt;

&lt;p&gt;The first &lt;code&gt;tiime auth login&lt;/code&gt; that actually worked, the first &lt;code&gt;tiime bank transactions&lt;/code&gt; returning real amounts... That's the moment the project shifted from "is this even possible?" to "how far can we take this?"&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F17301q4isecyet9zeqs8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F17301q4isecyet9zeqs8.png" alt="CLI terminal showing bank transactions and audit commands"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;First dopamine hit:&lt;/strong&gt; I asked Claude "Show me my latest transaction" — and through the Skill, it just answered.&lt;/p&gt;

&lt;h3&gt;
  
  
  Trust kicks in
&lt;/h3&gt;

&lt;p&gt;At this point, I realized the collaboration was working. I started delegating aggressively:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Go ahead, I trust you. Implement everything."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"Break down the work, spin up sub-agents in parallel, do whatever you want — just ship it."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Claude launched 6, 8, sometimes 10 sub-agents in parallel. One implementing invoices, another bank transactions, a third writing tests, a fourth building the retry system... My terminal exploded with activity.&lt;/p&gt;




&lt;h2&gt;
  
  
  Day 2 — The monorepo and the data leak
&lt;/h2&gt;

&lt;h3&gt;
  
  
  From monolith to monorepo
&lt;/h3&gt;

&lt;p&gt;The project was growing fast. Too fast for a single package. Time to restructure into a &lt;strong&gt;Turborepo monorepo&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;tiime/
├── packages/
│   ├── tiime-sdk/    # TypeScript SDK (zero dependencies)
│   └── tiime-cli/    # CLI (depends on the SDK)
├── apps/
│   └── docs/         # Fumadocs documentation
├── turbo.json
└── pnpm-workspace.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The SDK was designed to be &lt;strong&gt;as lightweight as possible&lt;/strong&gt;: zero production dependencies, native fetch, final bundle of 11 KB. The CLI could afford dependencies like &lt;code&gt;citty&lt;/code&gt; (CLI framework), &lt;code&gt;@clack/prompts&lt;/code&gt; (interactive prompts), and &lt;code&gt;cli-table3&lt;/code&gt; (table formatting).&lt;/p&gt;

&lt;p&gt;Turborepo handled build ordering automatically via the dependency graph: the SDK always builds before the CLI.&lt;/p&gt;

&lt;h3&gt;
  
  
  The incident that made me sweat
&lt;/h3&gt;

&lt;p&gt;Then came the most tense moment of the entire project.&lt;/p&gt;

&lt;p&gt;I had set up documentation with &lt;a href="https://fumadocs.vercel.app/" rel="noopener noreferrer"&gt;Fumadocs&lt;/a&gt;. Beautiful, clean, deployed on GitHub Pages. Until I noticed...&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"You put my real personal data in the docs?! On a public repo?!"&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Claude had used my real company names and real amounts in the documentation examples. On a public repository. With git history preserving everything.&lt;/p&gt;

&lt;p&gt;Panic. We had to replace everything with dummy data &lt;em&gt;and&lt;/em&gt; &lt;strong&gt;rewrite the git history&lt;/strong&gt; to erase all traces. Force push on main. The kind of moment that reminds you: AI doesn't understand personal data — you have to be explicit.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lesson #1: Always review what goes public. AI optimizes for realistic examples, not confidentiality.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The docs, after the scare
&lt;/h3&gt;

&lt;p&gt;Once the incident was behind us, the documentation site turned out great. Fumadocs + Next.js as a static export, auto-deployed on GitHub Pages. Every CLI command and SDK method documented with examples — fictional ones this time.&lt;/p&gt;




&lt;h2&gt;
  
  
  Day 3 — The audit feature and the CI war
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Multi-company audit
&lt;/h3&gt;

&lt;p&gt;This was the feature I actually built the whole thing for: automated account auditing.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"I want a full audit of all my accounts. Detect what's uncategorized and auto-fix it across all my companies at once."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The &lt;code&gt;tiime audit&lt;/code&gt; command scans all uncategorized transactions, suggests labels via Tiime's suggestion API, and can apply corrections automatically:&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;# Dry-run across all companies&lt;/span&gt;
tiime audit &lt;span class="nt"&gt;--all-companies&lt;/span&gt;

&lt;span class="c"&gt;# Apply corrections&lt;/span&gt;
tiime audit &lt;span class="nt"&gt;--all-companies&lt;/span&gt; &lt;span class="nt"&gt;--apply&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is where the API quirks bit us. The &lt;code&gt;unimputed()&lt;/code&gt; endpoint sometimes returns just &lt;code&gt;{ id }&lt;/code&gt; — no &lt;code&gt;wording&lt;/code&gt;, no &lt;code&gt;amount&lt;/code&gt;. You have to re-fetch each transaction individually. The kind of silent bug that eats hours.&lt;/p&gt;

&lt;h3&gt;
  
  
  The CI/CD war
&lt;/h3&gt;

&lt;p&gt;If I had to name the single recurring technical battle of this project, it's CI/CD. We iterated at least ten times on the GitHub Actions workflows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Changesets&lt;/strong&gt; for semantic versioning&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Trusted Publishing (OIDC)&lt;/strong&gt; for npm — no secret tokens, authentication via OpenID Connect between GitHub and npmjs.com&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Provenance&lt;/strong&gt; enabled for package traceability&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Homebrew tap&lt;/strong&gt; auto-updated on every CLI release&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Coverage&lt;/strong&gt; computed and displayed via a dynamic badge&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every single component broke at least once. Trusted publishing is tied to the &lt;strong&gt;workflow file name&lt;/strong&gt; — rename &lt;code&gt;ci.yml&lt;/code&gt; to &lt;code&gt;release.yml&lt;/code&gt; and publishing silently fails. The Homebrew action wouldn't trigger because one workflow can't trigger another without &lt;code&gt;workflow_dispatch&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"CI is broken again, check what's going on."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I typed that sentence at least 10 times in 4 days.&lt;/p&gt;

&lt;p&gt;And sometimes frustration boiled over:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"That's wrong — the workflow is invalid, you didn't even check the syntax."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"The Homebrew workflow isn't even triggering!"&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Lesson #2: CI/CD is where AI struggles the most. It can't test a workflow locally — it's pure trial-and-error, and each attempt takes several minutes.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Day 4 — The dashboard and Money Wrapped
&lt;/h2&gt;

&lt;h3&gt;
  
  
  A financial cockpit in one command
&lt;/h3&gt;

&lt;p&gt;The idea came naturally: why not a visual dashboard?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"I want a financial dashboard. Not a separate Next.js project — just a CLI command that opens a web page with all the data."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The solution: &lt;code&gt;tiime dashboard&lt;/code&gt; spins up a tiny HTTP server on port 3141 and opens the browser. The backend serves data through &lt;code&gt;/api/*&lt;/code&gt; endpoints; the frontend is HTML/JS/CSS injected directly — no bundler, no framework, pure vanilla with Tailwind CDN and Chart.js.&lt;/p&gt;

&lt;h3&gt;
  
  
  Spotify Wrapped, but for money
&lt;/h3&gt;

&lt;p&gt;Then came the wild idea:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Add a Spotify Wrapped but for my finances. Storytelling with slides, stats, something fun."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And so &lt;strong&gt;Money Wrapped&lt;/strong&gt; was born — 11 full-screen slides that tell your financial year's story:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmk8aiop259qsfrsv1d2g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmk8aiop259qsfrsv1d2g.png" alt="Money Wrapped intro slide"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Intro&lt;/strong&gt; — "Your financial year in review"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Revenue&lt;/strong&gt; — total + invoice count&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Best month&lt;/strong&gt; — peak activity&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Top clients&lt;/strong&gt; — ranked by revenue&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cash flow&lt;/strong&gt; — inflows vs outflows&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monthly evolution&lt;/strong&gt; — line chart&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Top expenses&lt;/strong&gt; — main categories&lt;/li&gt;
&lt;li&gt;...and more&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Each slide has its own gradient, animations (incrementing counters, confetti, smooth transitions), plus keyboard, click, and touch-swipe navigation.&lt;/p&gt;

&lt;p&gt;Mobile rendering was a battle. CSS scroll-snap refused to cooperate:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"The snap on mobile still doesn't work, it scrolls all over the place."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We ended up switching to a &lt;code&gt;translateX&lt;/code&gt; approach with manual touch handling. Inelegant, but it works.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I actually learned about pair-programming with AI
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What works incredibly well
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Parallelization.&lt;/strong&gt; When I say "implement everything," Claude spins up sub-agents in isolated worktrees. One codes invoices, another writes tests, a third configures CI. Like having a team of 10 devs working simultaneously.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reverse-engineering.&lt;/strong&gt; For picking apart an undocumented API, AI is exceptional. It parses headers, detects pagination patterns, identifies data schemas — all faster than any human.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Boilerplate elimination.&lt;/strong&gt; Configuring a Turborepo monorepo, writing TypeScript types, setting up CI/CD workflows — anything structural and repetitive, AI crushes.&lt;/p&gt;

&lt;h3&gt;
  
  
  What demands vigilance
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Sensitive data.&lt;/strong&gt; The documentation incident taught me the hard way: always review what goes public. AI optimizes for example quality, not confidentiality.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cross-session memory.&lt;/strong&gt; This was my biggest frustration:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"We literally solved this exact problem yesterday. Why don't you remember?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"Why do I have to tell you to save important stuff? You should do that on your own."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Each new Claude Code session starts nearly from scratch. I learned to use the persistent memory system (&lt;code&gt;MEMORY.md&lt;/code&gt;) to store API gotchas, architectural decisions, and CI pitfalls. But you have to be proactive about it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CI/CD.&lt;/strong&gt; AI can't test a GitHub Actions workflow before pushing it. It's guess-and-check. Each iteration takes 2-3 minutes. Over 10 iterations, that's 30 minutes of waiting for something an experienced DevOps engineer might nail in 2 tries.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Visual polish.&lt;/strong&gt; For the Remotion video we attempted (and abandoned), or the Wrapped animations, AI produces &lt;em&gt;correct&lt;/em&gt; output but rarely &lt;em&gt;beautiful&lt;/em&gt; output on the first try. You need to iterate, guide, and sometimes say "no, not like that" several times.&lt;/p&gt;

&lt;h3&gt;
  
  
  The numbers
&lt;/h3&gt;

&lt;p&gt;In 4 days, we shipped:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;107 commits&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;2 npm packages&lt;/strong&gt; published (tiime-sdk v3.0.1, tiime-cli v2.2.0)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;14 CLI commands&lt;/strong&gt; with subcommands&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;10 SDK resources&lt;/strong&gt; (invoices, bank, clients, quotations, expenses...)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;1 documentation site&lt;/strong&gt; on GitHub Pages&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;1 financial dashboard&lt;/strong&gt; with Money Wrapped&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;1 Homebrew formula&lt;/strong&gt; auto-updated&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;1 Claude Code Skill&lt;/strong&gt; for natural language queries&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Unit tests&lt;/strong&gt; with coverage&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No solo developer sustains that pace. Not because the code writes itself — but because all the friction vanishes. The friction of looking up GitHub Actions syntax. The friction of remembering how to configure tsup. The friction of writing 400 lines of TypeScript types by hand.&lt;/p&gt;




&lt;h2&gt;
  
  
  The tech stack
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Choice&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;&lt;strong&gt;Monorepo&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Turborepo + pnpm&lt;/td&gt;
&lt;td&gt;Automatic build order, smart caching&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Language&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;TypeScript strict&lt;/td&gt;
&lt;td&gt;Type safety, DX, no &lt;code&gt;any&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;SDK HTTP&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Native &lt;code&gt;fetch&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Zero dependencies, 11 KB bundle&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;CLI framework&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Citty&lt;/td&gt;
&lt;td&gt;Lightweight, typed, nested subcommands&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Prompts&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;@clack/prompts&lt;/td&gt;
&lt;td&gt;Elegant interactive UX&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Build&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;tsup&lt;/td&gt;
&lt;td&gt;ESM-only, tree-shaking, minification&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Linter&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Biome&lt;/td&gt;
&lt;td&gt;Replaces ESLint + Prettier in one tool&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Tests&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Vitest&lt;/td&gt;
&lt;td&gt;Fast, native ESM compatible&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Docs&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Fumadocs + Next.js&lt;/td&gt;
&lt;td&gt;MDX, static export, GitHub Pages&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Dashboard&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Vanilla JS + Chart.js&lt;/td&gt;
&lt;td&gt;No framework, embedded in the CLI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;CI/CD&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;GitHub Actions + Changesets&lt;/td&gt;
&lt;td&gt;Trusted publishing OIDC, no npm secrets&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Distribution&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;npm + Homebrew&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;npm i -g tiime-cli&lt;/code&gt; or &lt;code&gt;brew install tiime&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  What I'd do again (and what I'd change)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Do again:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SDK-first architecture.&lt;/strong&gt; Separating the SDK from the CLI from day one. The SDK can live on its own — in a Node.js script, a server, another CLI.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;JSON-first output.&lt;/strong&gt; Every command returns parseable JSON. That's what makes the Skill possible.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Trusted publishing.&lt;/strong&gt; No npm tokens in GitHub secrets. OIDC is safer and cleaner.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Claude Code Skill.&lt;/strong&gt; Being able to say "what's my latest transaction?" in natural language and getting an answer — that's the real unlock.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Change:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Document gotchas from day 1.&lt;/strong&gt; I should have maintained a living file of API quirks from the start, not after wasting time rediscovering the same issues.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Write tests earlier.&lt;/strong&gt; We added them on day 3. When AI generates code fast, regressions arrive just as fast.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Build CI/CD incrementally.&lt;/strong&gt; Instead of configuring everything at once (lint + build + test + release + Homebrew + coverage + docs), I should have added each piece one at a time.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Conclusion: AI as an amplifier, not a replacement
&lt;/h2&gt;

&lt;p&gt;This isn't a story of "AI did everything." It's a story of &lt;strong&gt;intense pair-programming&lt;/strong&gt; where each side brings what they're best at.&lt;/p&gt;

&lt;p&gt;Me: the product vision, architectural decisions, quality control, and domain knowledge — what is transaction categorization? Why does multi-company auditing matter?&lt;/p&gt;

&lt;p&gt;Claude Code: execution speed, encyclopedic knowledge of tools, the ability to parallelize, and infinite patience with CI/CD iterations.&lt;/p&gt;

&lt;p&gt;The result? A tool I actually use every day to manage my accounting. A tool that didn't exist 4 days ago. A tool that, through its Skill, lets other AI agents interact with Tiime.&lt;/p&gt;

&lt;p&gt;The code is open source. The SDK is on npm. The CLI installs via Homebrew.&lt;/p&gt;

&lt;p&gt;And the next article? Probably the one where Tiime finally replies to my Instagram DM.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Built in 4 days (March 7-10, 2026). 107 commits. 2 npm packages. 1 developer. 1 AI. Too much coffee.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The project: &lt;a href="https://github.com/yabbal/tiime" rel="noopener noreferrer"&gt;tiime-cli on GitHub&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>cli</category>
      <category>typescript</category>
      <category>tooling</category>
    </item>
  </channel>
</rss>
