<?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: Jose Daniel Leon Ruiz</title>
    <description>The latest articles on DEV Community by Jose Daniel Leon Ruiz (@jdevleon).</description>
    <link>https://dev.to/jdevleon</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%2F4136592%2F0c0e5e02-1b52-4df2-9d9d-41229c500302.jpg</url>
      <title>DEV Community: Jose Daniel Leon Ruiz</title>
      <link>https://dev.to/jdevleon</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jdevleon"/>
    <language>en</language>
    <item>
      <title>The Rate-Limit Data Was Already in Claude Code's Own Logs</title>
      <dc:creator>Jose Daniel Leon Ruiz</dc:creator>
      <pubDate>Wed, 28 Oct 2026 14:45:14 +0000</pubDate>
      <link>https://dev.to/jdevleon/the-rate-limit-data-was-already-in-claude-codes-own-logs-730</link>
      <guid>https://dev.to/jdevleon/the-rate-limit-data-was-already-in-claude-codes-own-logs-730</guid>
      <description>&lt;p&gt;When Claude Code hits a rate limit, it doesn't just show you a banner and move on. It writes the full rate-limit response into your own session transcript — which window got hit, and exactly when it resets. Most people never look at that line again.&lt;br&gt;
We ran into this building &lt;strong&gt;estela plan&lt;/strong&gt;, a command that tells you whether your Claude subscription (Pro, Max 5x, Max 20x) actually fits how you work. The obvious way to answer that is to start sampling your usage percentage going forward — which is what we shipped first, in 0.2.4: the status line already reports a 5-hour and a 7-day percentage, so we log it locally every few minutes.&lt;br&gt;
But that only gives you data from the day you installed it. The real question — has this plan been blocking me — needs history, and we assumed there was none to recover.&lt;/p&gt;

&lt;h2&gt;
  
  
  It was already there
&lt;/h2&gt;

&lt;p&gt;Every time a request comes back as a 429, or Claude Code marks it rejected, it writes a &lt;strong&gt;quotaLimits&lt;/strong&gt; block into the JSONL transcript: the window type (&lt;strong&gt;five_hour&lt;/strong&gt; or &lt;strong&gt;seven_day&lt;/strong&gt;) and the timestamp it resets at. That's an official record from the tool itself, sitting on disk since before we wrote a single line of estela plan.&lt;br&gt;
So the hard part wasn't finding the data. It was reading it safely.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reading months of transcripts without re-reading months of transcripts
&lt;/h2&gt;

&lt;p&gt;A month of transcripts can run into hundreds of megabytes, across dozens of files that keep growing while Claude Code is running. Re-parsing everything on every check was never going to work, so the scanner keeps a byte offset per file and only reads what's new since last time.&lt;br&gt;
The detail that actually mattered: it never trusts the last line of what it just read. It cuts at the last complete newline and remembers that exact byte position, so a line that's half-written when we read it gets picked up whole on the next pass, instead of failing to parse, or worse, parsing a truncated JSON object into garbage.&lt;br&gt;
Matching is intentionally narrow: it only even attempts to parse a line if it contains the literal string quotaLimits, then checks that the window type is one of the two valid values, the reset timestamp is a real number, and the status actually indicates a block. Anything else, a malformed or partial line, is skipped, not guessed at.&lt;/p&gt;

&lt;h2&gt;
  
  
  A smaller lesson in the same release
&lt;/h2&gt;

&lt;p&gt;The plan prices and session multipliers Anthropic publishes are hardcoded in one small file, on purpose, with the exact date they were last checked against claude.com/pricing next to them. If that date is more than 90 days old, &lt;strong&gt;estela plan&lt;/strong&gt; says so instead of quietly showing a number that might not be true anymore. Anthropic doesn't publish how the weekly limit compares across plans at all, so that comparison is simply left out rather than estimated.&lt;/p&gt;

&lt;h2&gt;
  
  
  The actual takeaway
&lt;/h2&gt;

&lt;p&gt;Before you build a new logging layer on top of a tool, it's worth checking what that tool already wrote down when it failed. In this case, the monitoring we thought we had to start from zero already existed, as a side effect of Claude Code just doing its job honestly when it rejected a request.&lt;br&gt;
&lt;strong&gt;estela plan&lt;/strong&gt; is open source, part of the Estela CLI: &lt;a href="https://github.com/jdleonruiz/estela-cli?utm_source=devto&amp;amp;utm_medium=post&amp;amp;utm_campaign=429-blocks" rel="noopener noreferrer"&gt;github.com/jdleonruiz/estela-cli&lt;/a&gt;&lt;br&gt;
Have you found a case where the tool you were trying to monitor had already logged exactly what you needed?&lt;/p&gt;

</description>
      <category>claude</category>
      <category>showdev</category>
      <category>opensource</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Validating ID numbers from 7 Spanish-speaking countries with check digits</title>
      <dc:creator>Jose Daniel Leon Ruiz</dc:creator>
      <pubDate>Tue, 27 Oct 2026 15:32:54 +0000</pubDate>
      <link>https://dev.to/jdevleon/validating-id-numbers-from-7-spanish-speaking-countries-with-check-digits-bbh</link>
      <guid>https://dev.to/jdevleon/validating-id-numbers-from-7-spanish-speaking-countries-with-check-digits-bbh</guid>
      <description>&lt;p&gt;People paste contracts, client lists and bank emails into ChatGPT every day. We built &lt;a href="https://github.com/zaisor-technology/veloprompt?utm_source=devto&amp;amp;utm_medium=post&amp;amp;utm_campaign=lanzamiento-veloprompt" rel="noopener noreferrer"&gt;VeloPrompt&lt;/a&gt;, an open-source (MIT) browser extension that spots personal data before it reaches an AI chat and swaps it for labels like [CEDULA_1] or [IBAN_1]. The AI works with the labels; the real values come back only on your screen.&lt;br&gt;
Most tools in this space are built around US and English formats. Our users are in Spain and Latin America, where the sensitive numbers are a cédula, a RUC, a DNI, a CURP or a RUT. This post is about the part that took the most care: detecting those numbers without flagging every order ID and invoice amount.&lt;/p&gt;

&lt;h2&gt;
  
  
  Shape is not enough
&lt;/h2&gt;

&lt;p&gt;A 10-digit number can be an Ecuadorian cédula, a phone number, an order ID or a timestamp. If you match by shape alone, the extension warns on everything and people turn it off. So every rule validates the number's own check digit before it counts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three examples
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Ecuador, cédula (modulo 10).&lt;/strong&gt; The first two digits are the province (01-24 or 30). Multiply the first nine digits by 2,1,2,1,..., subtract 9 from any product above 9, sum them, and the check digit is (10 - sum mod 10) mod 10.&lt;br&gt;
&lt;strong&gt;Spain, DNI/NIF (letter).&lt;/strong&gt; The letter is "TRWAGMYFPDXBNJZSQVHLCKE"[number mod 23]. For a NIE, replace the leading X, Y or Z with 0, 1 or 2 and apply the same rule.&lt;br&gt;
&lt;strong&gt;Chile, RUT (modulo 11).&lt;/strong&gt; Multiply the digits from right to left by 2,3,4,5,6,7 (and repeat), take 11 - (sum mod 11); 11 means 0 and 10 means K. It has to accept both 12.345.678-5 and 12345678-5.&lt;br&gt;
The same idea covers Mexico (CURP, RFC, CLABE), Colombia (NIT), Peru (RUC), Argentina (CUIT/CUIL, CBU), Spanish CIF and IBANs (mod 97), plus cards with Luhn.&lt;/p&gt;

&lt;h2&gt;
  
  
  When there is no check digit
&lt;/h2&gt;

&lt;p&gt;A Peruvian DNI or a Colombian cédula has no checksum. For those, the number only counts if a context word is nearby ("DNI", "C.C.", "cédula"). And a valid-looking number is still ignored if it follows words like "pedido", "factura" or "seguimiento", or looks like an amount.&lt;br&gt;
When two rules match the same number (a Peruvian RUC and an Argentine CUIT that both start with 20 share the same arithmetic), the one with context wins. Either way the value gets masked; only the label can differ.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing without real people
&lt;/h2&gt;

&lt;p&gt;The test suite never uses real documents. A separate generator builds valid numbers with its own implementation of each algorithm, so the tests do not validate the code against itself. Each rule is tested with valid numbers, numbers with a wrong check digit (which must not match) and look-alikes such as order IDs and dates. detect() runs on 50,000 characters in about 3 ms.&lt;/p&gt;

&lt;h2&gt;
  
  
  Everything stays local
&lt;/h2&gt;

&lt;p&gt;The engine (veloprompt-core) is plain TypeScript with no runtime dependencies. The extension makes no network requests, and the label-to-value map lives only in the tab's memory.&lt;br&gt;
Each country is one rules file with its tests, so adding a country is a small, self-contained pull request. If you work with IDs from a country we do not cover yet, we would love the contribution: &lt;a href="https://github.com/zaisor-technology/veloprompt?utm_source=devto&amp;amp;utm_medium=post&amp;amp;utm_campaign=lanzamiento-veloprompt" rel="noopener noreferrer"&gt;github.com/zaisor-technology/veloprompt&lt;/a&gt;&lt;br&gt;
What do you do today to keep personal data out of AI chats?&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>opensource</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Why "Approved" From a Payment Gateway Isn't Enough</title>
      <dc:creator>Jose Daniel Leon Ruiz</dc:creator>
      <pubDate>Thu, 22 Oct 2026 16:45:50 +0000</pubDate>
      <link>https://dev.to/jdevleon/why-approved-from-a-payment-gateway-isnt-enough-3ch8</link>
      <guid>https://dev.to/jdevleon/why-approved-from-a-payment-gateway-isnt-enough-3ch8</guid>
      <description>&lt;p&gt;If your payment gateway responds with approved: true, do you also check that the approved amount matches what you asked it to charge?&lt;br&gt;
We didn't, until this week.&lt;br&gt;
We're building DymCore, an invoicing platform for small businesses, and one of its payment integrations is PayPhone, a payment gateway used in Ecuador. Like most integrations, our code trusted the boolean the gateway returned: if PayPhone said the transaction was approved, we marked the order as paid.&lt;br&gt;
The boolean told us the transaction went through. It never told us it went through for the right amount.&lt;br&gt;
This week we added an explicit check before confirming any order: compare the amount PayPhone approved against the amount we expected to charge. If they don't match, the payment isn't silently accepted. It raises a critical alert and the order stays unconfirmed instead of moving forward.&lt;br&gt;
We also added dedicated test coverage for the mismatch case specifically, because this is exactly the kind of check you want to be sure never regresses silently.&lt;br&gt;
The lesson generalizes past this one gateway: when a third-party system tells you "this succeeded," the amount is usually the part worth re-verifying server-side, not just the success flag. A field saying "approved" is a claim from someone else's system, not a receipt you generated yourself.&lt;br&gt;
Have you run into a payment or billing integration that approved a different amount than what was requested? Curious how other teams guard against this.&lt;br&gt;
We write about things like this while building &lt;a href="https://dymcore.com/?utm_source=devto&amp;amp;utm_medium=post&amp;amp;utm_campaign=payphone-amount-check" rel="noopener noreferrer"&gt;DymCore&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>security</category>
      <category>webdev</category>
      <category>fintech</category>
    </item>
    <item>
      <title>Logging Your Own Rate-Limit History (Since Claude Code Won't)</title>
      <dc:creator>Jose Daniel Leon Ruiz</dc:creator>
      <pubDate>Tue, 20 Oct 2026 15:30:06 +0000</pubDate>
      <link>https://dev.to/jdevleon/logging-your-own-rate-limit-history-since-claude-code-wont-5fhb</link>
      <guid>https://dev.to/jdevleon/logging-your-own-rate-limit-history-since-claude-code-wont-5fhb</guid>
      <description>&lt;p&gt;Claude Code's status line will tell you you're at 73% of your 5-hour window. What it won't tell you is whether you got there gradually over four hours, or in the ten minutes after you dumped a huge file into context.&lt;br&gt;
That distinction matters more than the number itself. A slow drain means you can keep working and watch it. A sharp spike means something in your workflow is burning quota fast, and you won't know what unless you were staring at the screen when it happened.&lt;br&gt;
The problem is structural, not a bug: the percentage Claude Code reports is a live reading with no memory. The moment it updates, the previous value is gone. There's no file, no log, nothing to look back on after the fact.&lt;br&gt;
We ran into this building Estela, the open-source tool we're building to reconstruct billable hours from your coding agent sessions, so in the latest version we started keeping that history ourselves.&lt;br&gt;
It's a plain local log, ~/.estela/rate-limits.jsonl, one line per sample. The sampling is deliberately sparse: at most once every 5 minutes, unless the percentage moves by at least a point or a new reset window starts - no point logging the same number forty times an hour. Entries older than 120 days get pruned automatically. Each line stores exactly three things: the percentage, its reset time, and the Claude Code version that reported it. No session content, no file paths, no project names, and nothing leaves your machine.&lt;br&gt;
One limitation worth being upfront about: Claude Code's own transcripts don't carry these percentages, so there's no way to reconstruct history retroactively. The log starts the day you update.&lt;br&gt;
Small related note if you rely on it: the status line only renders in Claude Code's terminal - the VS Code extension doesn't show it at all.&lt;br&gt;
We're not shipping an analysis view on top of this yet - that's a line we're exploring, not a feature that exists today - but the log is there now, in case you want to query it yourself before we do.&lt;br&gt;
Repo, if you're curious how it's wired: &lt;a href="https://github.com/jdleonruiz/estela-cli?utm_source=devto&amp;amp;utm_medium=post&amp;amp;utm_campaign=rate-history" rel="noopener noreferrer"&gt;github.com/jdleonruiz/estela-cli&lt;/a&gt;&lt;br&gt;
Do you track your own rate-limit usage over time, or only find out the shape of it after you've already hit the wall?&lt;/p&gt;

</description>
      <category>claude</category>
      <category>showdev</category>
      <category>opensource</category>
      <category>productivity</category>
    </item>
    <item>
      <title>What clients actually mean when they ask "did you use AI for this?"</title>
      <dc:creator>Jose Daniel Leon Ruiz</dc:creator>
      <pubDate>Fri, 16 Oct 2026 15:30:27 +0000</pubDate>
      <link>https://dev.to/jdevleon/what-clients-actually-mean-when-they-ask-did-you-use-ai-for-this-l11</link>
      <guid>https://dev.to/jdevleon/what-clients-actually-mean-when-they-ask-did-you-use-ai-for-this-l11</guid>
      <description>&lt;p&gt;A client asking "did you use AI for this?" rarely means what it sounds like.&lt;br&gt;
Keito, a billing platform built around AI-assisted agency work, put it plainly in a recent post: &lt;a href="https://keito.ai/blog/billing-clients-for-ai-work/" rel="noopener noreferrer"&gt;"Clients demand visibility into whether AI was used and what value it delivered."&lt;/a&gt; That's two different questions wearing one sentence.&lt;br&gt;
The first one — did you use it — is rarely what they actually care about. Nobody refuses a chair because a machine cut the wood. What they're really asking, even when they don't phrase it that way, is closer to: can you show me the work happened, and was it worth what I'm paying?&lt;br&gt;
A token count doesn't answer that. A client doesn't know what a token is, and an invoice line that says "4.5 hours" doesn't say whether those hours built the feature or re-read the same three files after a failed attempt.&lt;br&gt;
What answers it is closer to a paper trail: hours that map to commits, commits that map to a shipped feature, on a timeline the client can open without pinging you for a status update. Not a transparency stunt — just evidence that survives a second look.&lt;br&gt;
That's the part already built into &lt;a href="https://github.com/jdleonruiz/estela-cli?utm_source=devto&amp;amp;utm_medium=post&amp;amp;utm_campaign=client-transparency" rel="noopener noreferrer"&gt;Estela&lt;/a&gt;, the open-source tool we're building: a read-only panel, one per client, from the hours and cost it reconstructs locally from Claude Code and Codex session logs plus git. The client opens a link instead of asking you for an update.&lt;br&gt;
If you bill clients for work an agent touched, what do you actually show them when they ask?&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>freelancing</category>
      <category>opensource</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Which project ate my Claude Code quota?</title>
      <dc:creator>Jose Daniel Leon Ruiz</dc:creator>
      <pubDate>Thu, 15 Oct 2026 15:15:03 +0000</pubDate>
      <link>https://dev.to/jdevleon/which-project-ate-my-claude-code-quota-1p2a</link>
      <guid>https://dev.to/jdevleon/which-project-ate-my-claude-code-quota-1p2a</guid>
      <description>&lt;p&gt;You're on a flat plan, it's mid-afternoon, and Claude Code tells you you've hit your limit. The usage screen confirms it. What it doesn't tell you is where it went.&lt;br&gt;
If you work on one repo, that's annoying. If you work on four, or you launch subagents, it's the question that matters: which project used it?&lt;br&gt;
So I added a command to &lt;a href="https://github.com/jdleonruiz/estela-cli" rel="noopener noreferrer"&gt;Estela&lt;/a&gt;, the open-source CLI I'm building: &lt;strong&gt;estela quota&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it shows
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Tokens per project for the &lt;strong&gt;current 5-hour window&lt;/strong&gt; and for &lt;strong&gt;this week&lt;/strong&gt; (Monday to today, in your time zone).&lt;/li&gt;
&lt;li&gt;Input, output, cache read and cache write as separate numbers, because they don't weigh the same.&lt;/li&gt;
&lt;li&gt;This week against the &lt;strong&gt;average of your previous 4 weeks&lt;/strong&gt; over the same stretch of days, so you can tell a heavy week from a normal one.&lt;/li&gt;
&lt;li&gt;Claude Code and Codex shown separately: they draw on different quotas.
There's also a &lt;strong&gt;--json&lt;/strong&gt; flag for scripts, and the same breakdown is a card in the Summary tab of the local dashboard (&lt;strong&gt;estela web&lt;/strong&gt;).
## What it refuses to do
It never tells you how much you have left.
Neither Anthropic nor OpenAI publish their plans' limits, so any "X tokens left" or "you'll run out on Thursday" would be a made-up number. On top of that, anything you use on claude.ai or on another machine counts against the same quota but never touches this disk.
The 5-hour window is labeled as an estimate for the same reason: how its start gets rounded isn't public.
I'd rather show real consumption with an honest caveat than a precise-looking countdown that's wrong.
## Where the numbers come from
Claude Code already writes every session to &lt;strong&gt;~/.claude/projects/&lt;/strong&gt; as JSONL, and Codex to &lt;strong&gt;~/.codex/sessions/&lt;/strong&gt;. Estela reads those files, dedupes repeated turns (Claude Code can write the same turn several times), and maps each session to a project by its working directory. Nothing leaves your machine.
Copilot is left out of this view: its local logs don't record reliable token counts.
## Try it
&lt;strong&gt;npx estela setup&lt;/strong&gt;, then &lt;strong&gt;estela quota&lt;/strong&gt;.
It's free, MIT, zero runtime dependencies. If you've ever burned through a limit and couldn't tell why, I'd like to hear what ate it. And if you find a case where the numbers look wrong, an issue on &lt;a href="https://github.com/jdleonruiz/estela-cli" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; helps a lot.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>claude</category>
      <category>showdev</category>
      <category>opensource</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Your AI cost dashboard tells you how much. Not why.</title>
      <dc:creator>Jose Daniel Leon Ruiz</dc:creator>
      <pubDate>Tue, 13 Oct 2026 20:51:13 +0000</pubDate>
      <link>https://dev.to/jdevleon/your-ai-cost-dashboard-tells-you-how-much-not-why-1hof</link>
      <guid>https://dev.to/jdevleon/your-ai-cost-dashboard-tells-you-how-much-not-why-1hof</guid>
      <description>&lt;p&gt;A cost dashboard tells you how much you spent. It almost never tells you why.&lt;br&gt;
$340 in exploration — an agent re-reading the same three files across five failed attempts before it finds the right approach — looks identical, on most dashboards, to $340 that shipped a feature. Same currency, same token count, completely different story.&lt;br&gt;
A breakdown of Anthropic's enterprise analytics on Finout put it well: the console can tell you how much a workspace spent, but &lt;a href="https://www.finout.io/blog/anthropics-enterprise-analytics" rel="noopener noreferrer"&gt;"what it can't tell you is which human beings caused it"&lt;/a&gt; — or, I'd add, what kind of work caused it. Someone asked for exactly this gap to be closed in a &lt;a href="https://dev.to/pederaa/how-to-track-claude-code-usage-in-2026-built-in-commands-ccusage-and-desktop-dashboards-compared-1kk1"&gt;dev.to comment&lt;/a&gt;: "I want cost by workflow shape: exploration, implementation, review, failed attempts, and rework."&lt;br&gt;
That's a harder thing to build than it sounds.&lt;br&gt;
To classify a session by workflow shape you'd need to correlate agent logs (which you have) with what actually reached a commit (which lives somewhere else entirely — git, not the session file). And even then the signal is messy: not every expensive exploration is waste. Sometimes five failed attempts are what make the sixth one land in two minutes instead of twenty. A shape-based view that treats all "exploration" cost as bad would just train people to stop exploring, which is worse.&lt;br&gt;
Where this is actually useful, I think, is pattern-spotting over weeks, not judging a single session. A project where exploration cost keeps climbing relative to shipped cost is telling you something — maybe the codebase got harder to navigate, maybe the task descriptions got vaguer. A project where it stays flat is probably fine. You only notice either way if cost is tagged with some notion of what the work was, not just a daily total.&lt;br&gt;
It's a line we're exploring for &lt;a href="https://github.com/jdleonruiz/estela-cli?utm_source=devto&amp;amp;utm_medium=post&amp;amp;utm_campaign=cost-workflow-shape" rel="noopener noreferrer"&gt;Estela&lt;/a&gt;, the open-source CLI we're building that already splits AI cost and hours by project from your local Claude Code and Codex logs. Linking cost to commits to tell apart exploration-that-paid-off from exploration-that-didn't is the next question on the list, not one it answers today.&lt;br&gt;
If your dashboard showed cost by workflow shape instead of by day, would you actually change anything?&lt;/p&gt;

</description>
      <category>claude</category>
      <category>showdev</category>
      <category>opensource</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Why Your AI Cost Dashboard Never Matches Your Invoice</title>
      <dc:creator>Jose Daniel Leon Ruiz</dc:creator>
      <pubDate>Thu, 08 Oct 2026 22:56:55 +0000</pubDate>
      <link>https://dev.to/jdevleon/why-your-ai-cost-dashboard-never-matches-your-invoice-4eba</link>
      <guid>https://dev.to/jdevleon/why-your-ai-cost-dashboard-never-matches-your-invoice-4eba</guid>
      <description>&lt;p&gt;If you've ever looked at a token counter after a long session with Claude Code, Codex, or Copilot and tried to reconcile it with your actual bill, you've probably hit a wall. Here's why that number is structurally unreliable, not just imprecise.&lt;br&gt;
&lt;strong&gt;1. Most dashboards show list-price tokens, not what you paid.&lt;/strong&gt;&lt;br&gt;
Anthropic's own docs are explicit about it: spend figures in the Claude Code console "are estimates for analytics purposes" (&lt;a href="https://code.claude.com/docs/en/analytics?utm_source=devto&amp;amp;utm_medium=post&amp;amp;utm_campaign=cost-estimate" rel="noopener noreferrer"&gt;https://code.claude.com/docs/en/analytics?utm_source=devto&amp;amp;utm_medium=post&amp;amp;utm_campaign=cost-estimate&lt;/a&gt;). If you're on a flat-rate plan like Max or Copilot Business, there's no per-request price at all — you're paying for a quota, and the tool still shows you an API-equivalent cost that has nothing to do with your invoice.&lt;br&gt;
&lt;strong&gt;2. Cache pricing moves 60-75% between model launches, and nothing recalculates your old numbers.&lt;/strong&gt;&lt;br&gt;
Teams that set quarterly token budgets are already redoing that math by hand after this quarter's model releases changed cache pricing — it's a live complaint on LinkedIn right now, not a hypothetical.&lt;br&gt;
&lt;strong&gt;3. Flat-rate limits track what's reserved, not what's used.&lt;/strong&gt;&lt;br&gt;
Developers have reported burning through a full Claude Max quota in about an hour of work instead of lasting a full day (&lt;a href="https://www.devclass.com/ai-ml/2026/04/01/anthropic-admits-claude-code-users-hitting-usage-limits-way-faster-than-expected/?utm_source=devto&amp;amp;utm_medium=post&amp;amp;utm_campaign=cost-estimate" rel="noopener noreferrer"&gt;https://www.devclass.com/ai-ml/2026/04/01/anthropic-admits-claude-code-users-hitting-usage-limits-way-faster-than-expected/?utm_source=devto&amp;amp;utm_medium=post&amp;amp;utm_campaign=cost-estimate&lt;/a&gt;), and some found their own console analytics blank when they went looking for an explanation (&lt;a href="https://www.theregister.com/2026/01/05/claude_devs_usage_limits/?utm_source=devto&amp;amp;utm_medium=post&amp;amp;utm_campaign=cost-estimate" rel="noopener noreferrer"&gt;https://www.theregister.com/2026/01/05/claude_devs_usage_limits/?utm_source=devto&amp;amp;utm_medium=post&amp;amp;utm_campaign=cost-estimate&lt;/a&gt;). There's no visibility into which project or session actually consumed the quota.&lt;br&gt;
&lt;strong&gt;4. None of the usage dashboards know about your git history.&lt;/strong&gt;&lt;br&gt;
A GitHub Discussions thread on Copilot usage metrics puts it plainly: "I need project-level attribution to charge development costs to the correct application" (&lt;a href="https://github.com/orgs/community/discussions/207634" rel="noopener noreferrer"&gt;https://github.com/orgs/community/discussions/207634&lt;/a&gt;). An open ccusage issue asks for the same thing (&lt;a href="https://github.com/ryoppippi/ccusage/issues/281" rel="noopener noreferrer"&gt;https://github.com/ryoppippi/ccusage/issues/281&lt;/a&gt;). Vendors meter by workspace or seat. Nobody meters by project or client, because that mapping only lives in your repo.&lt;br&gt;
Put together, these four gaps mean the number on your screen and the number on your invoice are measuring different things on purpose, not by mistake.&lt;br&gt;
We ran into this building Estela (&lt;a href="https://github.com/jdleonruiz/estela-cli?utm_source=devto&amp;amp;utm_medium=post&amp;amp;utm_campaign=cost-estimate" rel="noopener noreferrer"&gt;https://github.com/jdleonruiz/estela-cli?utm_source=devto&amp;amp;utm_medium=post&amp;amp;utm_campaign=cost-estimate&lt;/a&gt;), an open-source CLI that reconstructs hours and AI cost per project and client from your local agent logs and git history instead of trusting any single vendor's dashboard. It doesn't solve the pricing-page problem — nothing can, short of vendors publishing real per-request invoices — but it gives you your own numbers to check against theirs.&lt;br&gt;
Have you found a reliable way to reconcile what a tool shows you against what you actually get billed?&lt;/p&gt;

</description>
      <category>claude</category>
      <category>showdev</category>
      <category>ai</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Three coding agents, three log formats, three ways to get your hours wrong</title>
      <dc:creator>Jose Daniel Leon Ruiz</dc:creator>
      <pubDate>Thu, 01 Oct 2026 16:16:45 +0000</pubDate>
      <link>https://dev.to/jdevleon/three-coding-agents-three-log-formats-three-ways-to-get-your-hours-wrong-4m0m</link>
      <guid>https://dev.to/jdevleon/three-coding-agents-three-log-formats-three-ways-to-get-your-hours-wrong-4m0m</guid>
      <description>&lt;p&gt;Claude Code, Codex and GitHub Copilot all keep a local record of what you did with them. If you bill by the hour, or just want to know what a feature really cost, that record is gold: every turn has a timestamp, and most have a model and token counts.&lt;br&gt;
I've spent the last months turning those files into timesheets for &lt;a href="https://github.com/jdleonruiz/estela-cli" rel="noopener noreferrer"&gt;Estela&lt;/a&gt;, an open-source CLI. The hard part wasn't the reporting. It was that each agent stores its history in a different shape, and each shape has a way to quietly give you the wrong number.&lt;br&gt;
Here's what I found, agent by agent.&lt;/p&gt;

&lt;h2&gt;
  
  
  Claude Code: the same turn, up to five times
&lt;/h2&gt;

&lt;p&gt;Sessions live in &lt;strong&gt;~/.claude/projects/&lt;/strong&gt;, one JSONL file per session. Each line is an event, and assistant turns carry a usage block with input, output and cache tokens.&lt;br&gt;
The trap: a single assistant turn can appear in several rows (I've seen up to five) with identical usage. The file is a stream of updates, not a list of unique turns. Sum usage per row and your cost comes out about &lt;strong&gt;2.9x&lt;/strong&gt; too high on real sessions.&lt;br&gt;
The fix is boring: dedupe by &lt;strong&gt;message.id&lt;/strong&gt; before summing anything. Then, for time, group turns into work blocks: consecutive turns close together belong to the same stretch of work; a long gap starts a new one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Codex: running totals and cache in the wrong place
&lt;/h2&gt;

&lt;p&gt;Codex writes to &lt;strong&gt;~/.codex/sessions/&lt;/strong&gt;. Token usage arrives in token_count events, and each one carries two values: &lt;strong&gt;last_token_usage&lt;/strong&gt; (this call) and &lt;strong&gt;total_token_usage&lt;/strong&gt; (the session so far).&lt;br&gt;
Trap one: sum the totals and you count every earlier call again on each event. On a real 68-event session that multiplied cost by &lt;strong&gt;6&lt;/strong&gt;. Summing the "last" values matched the final total exactly, which is a nice self-check to keep in your tests.&lt;br&gt;
Trap two is subtler. Codex reports cached tokens inside input_tokens. Anthropic does the opposite and reports cache reads separately. If your code assumes one convention and reads the other, the cached part is billed at full input price and again at the cache price. On real data that turned &lt;strong&gt;$2.17 into $10.03&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  GitHub Copilot: a log you have to replay
&lt;/h2&gt;

&lt;p&gt;Copilot in VS Code keeps chats per workspace, under &lt;strong&gt;workspaceStorage//chatSessions&lt;/strong&gt;. Older files are plain JSON. Newer ones are JSONL, and they don't contain the chat at all. They contain the changes that built it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;kind 0: the initial state&lt;/li&gt;
&lt;li&gt;kind 1: set a value at a path&lt;/li&gt;
&lt;li&gt;kind 2: append to an array (optionally truncating first)&lt;/li&gt;
&lt;li&gt;kind 3: delete
Read only the first line and you get an empty chat. You have to replay every change in order to reach the final state, and only then look at the requests.
Once replayed, time is the easy part: each request has a start timestamp and a &lt;strong&gt;completedAt&lt;/strong&gt;. In agent mode that span can be several minutes of real work that no timer would have caught.
Two decisions I made for Copilot:&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inline completions leave nothing on disk.&lt;/strong&gt; That time can only come from commits, so it's labeled estimated, never measured.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cost stays empty.&lt;/strong&gt; Copilot is a flat subscription. Multiplying tokens by API prices would produce a number nobody paid. An honest blank beats a precise-looking guess.
## The rule that ties it together
Across all three, the principle I ended up with is: &lt;strong&gt;never mix measured and estimated without a label.&lt;/strong&gt; Hours rebuilt from session timestamps are measured. Hours inferred from commits alone (hand-written code, or tools that leave no log) are estimates, and should err on the short side because someone is paying for them.
Same with money. On a flat plan, the real AI cost of a project is your subscription split by how much each project used, not tokens at list price.
## If you're parsing these files yourself&lt;/li&gt;
&lt;li&gt;Claude Code: dedupe by message.id.&lt;/li&gt;
&lt;li&gt;Codex: sum last_token_usage, never the totals; subtract cached tokens from input.&lt;/li&gt;
&lt;li&gt;Copilot: replay the JSONL change log before reading anything.&lt;/li&gt;
&lt;li&gt;Write a test that compares your sum against the agent's own final total when it has one.
Or skip all of it: Estela does this locally, no account, zero dependencies, MIT.
&lt;strong&gt;npx estela setup&lt;/strong&gt;
Code: &lt;a href="https://github.com/jdleonruiz/estela-cli" rel="noopener noreferrer"&gt;https://github.com/jdleonruiz/estela-cli&lt;/a&gt;
Gemini CLI is the next agent I'd like to support, and there's an open issue for it. If you know how it stores sessions, a comment there would help a lot. And if you've hit other traps in these logs, I'd love to hear them.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>claude</category>
      <category>showdev</category>
      <category>opensource</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Hourly billing isn't dead if you can prove the hours</title>
      <dc:creator>Jose Daniel Leon Ruiz</dc:creator>
      <pubDate>Tue, 29 Sep 2026 16:00:57 +0000</pubDate>
      <link>https://dev.to/jdevleon/hourly-billing-isnt-dead-if-you-can-prove-the-hours-18nl</link>
      <guid>https://dev.to/jdevleon/hourly-billing-isnt-dead-if-you-can-prove-the-hours-18nl</guid>
      <description>&lt;p&gt;There's a good debate going on about how freelancers should price work now that an AI agent does part of it. Mark Fulton's &lt;a href="https://dev.to/markfulton/freelance-developer-rates-in-2026-how-to-price-work-an-ai-agent-can-half-do-14fc"&gt;Freelance Developer Rates in 2026&lt;/a&gt; makes the case for moving away from hourly billing, and a lot of it is right: you shouldn't invoice hours you no longer spend, and review and judgment are where the value is now.&lt;/p&gt;

&lt;p&gt;But I think hourly billing is getting blamed for a different problem. The problem isn't the unit. It's that almost nobody actually knows their hours.&lt;/p&gt;

&lt;h2&gt;
  
  
  The timer was always the weak part
&lt;/h2&gt;

&lt;p&gt;I bill clients by the hour. For years my "time tracking" was a timer I forgot to start, followed by a Friday afternoon reconstructing the week from memory and git log. Everyone I know who bills hourly does some version of this. The numbers that end up on the invoice are, charitably, estimates.&lt;/p&gt;

&lt;p&gt;That was already shaky before AI. With an agent in the loop it gets worse, because the work doesn't look like typing anymore. It's writing a prompt, reading what comes back, running it, pushing back, reviewing a diff. None of that shows up as keystrokes, and it's exactly the "review and judgment" part everyone agrees is valuable.&lt;/p&gt;

&lt;h2&gt;
  
  
  The agent is already keeping the log
&lt;/h2&gt;

&lt;p&gt;Here's the part that surprised me: the agent is a better timekeeper than I ever was.&lt;/p&gt;

&lt;p&gt;Claude Code writes every session to ~/.claude/projects/. Codex writes to ~/.codex/sessions/. Each turn has a timestamp, the model, and the exact token counts. Your git history says what shipped and when. Put those together and you can rebuild where the time went, per project, without anyone starting a timer.&lt;/p&gt;

&lt;p&gt;So instead of "stop billing hours", the option I'd add is: &lt;strong&gt;bill hours you can prove.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What "provable" means in practice
&lt;/h2&gt;

&lt;p&gt;When I started turning those logs into timesheets, three things turned out to matter more than I expected.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Keep measured and estimated apart.&lt;/strong&gt; Time rebuilt from agent sessions is measured: it has timestamps. Time inferred from commits alone (code written by hand, or with a tool that doesn't leave session logs) is an estimate. Those two should never be added into one number without a label. A client can accept an estimate; what breaks trust is finding out later that a "measured" number was a guess. And when you estimate, err on the short side, because someone is paying for it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. AI cost is a real line item, and it's easy to get wrong.&lt;/strong&gt; If you're on a flat subscription, your real cost per project isn't the sum of tokens at list price, it's the fee split by how much each project used. And the raw logs have traps. In Claude Code transcripts the same turn can appear up to five times with identical usage, so summing rows inflates cost about 2.9x. In Codex, each event carries both a per-call and a running total, and summing the running totals gave me 6x on a real session. Codex also counts cache inside the input tokens, the opposite of Anthropic's format: not subtracting it turned $2.17 into $10.03. If you're going to pass AI cost through to a client, or just decide whether a project is profitable, those multipliers matter.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Let the client see the evidence.&lt;/strong&gt; "I worked 42 hours" invites a negotiation. "Here are the 42 hours, and each block links to the commits it produced" mostly doesn't. The most useful thing I built was a read-only view I can send a client, where every number drills down to the work behind it.&lt;/p&gt;

&lt;h2&gt;
  
  
  So, hourly or value-based?
&lt;/h2&gt;

&lt;p&gt;Honestly, both, depending on the client. Fixed-scope and outcome pricing are great when the scope is clear. But a lot of real client work is open-ended maintenance, "can you also look at…" requests, and retainers, and for those hours are still the fairest unit anyone has found. What changed is that we can finally measure them instead of reconstructing them on Friday.&lt;/p&gt;

&lt;p&gt;And even if you move to value pricing, you still want the numbers. Knowing that a project took 30 measured hours and $40 of AI is how you find out whether your fixed price was a good idea.&lt;/p&gt;

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

&lt;p&gt;I turned this into an open-source CLI called &lt;a href="https://github.com/jdleonruiz/estela-cli" rel="noopener noreferrer"&gt;Estela&lt;/a&gt;. It reads your Claude Code, Codex and GitHub Copilot sessions plus your git history, and rebuilds your hours and AI cost per project and client. It runs entirely on your machine: no account, zero runtime dependencies, MIT licensed, and it never stores the content of your prompts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;npx estela setup&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It marks measured vs estimated hours, splits a flat subscription across projects, can either absorb the AI cost or pass it through to the client's report, and publishes a read-only panel you can share. Code and docs: &lt;a href="https://github.com/jdleonruiz/estela-cli" rel="noopener noreferrer"&gt;https://github.com/jdleonruiz/estela-cli&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you bill by the hour, I'd really like to know how you handle this today, and whether "measured vs estimated" is how you'd want to show time to a client.&lt;/p&gt;

</description>
      <category>claude</category>
      <category>showdev</category>
      <category>freelancing</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Our MCP server had been live for weeks. Nobody could see what it did.</title>
      <dc:creator>Jose Daniel Leon Ruiz</dc:creator>
      <pubDate>Thu, 24 Sep 2026 14:08:30 +0000</pubDate>
      <link>https://dev.to/jdevleon/our-mcp-server-had-been-live-for-weeks-nobody-could-see-what-it-did-323d</link>
      <guid>https://dev.to/jdevleon/our-mcp-server-had-been-live-for-weeks-nobody-could-see-what-it-did-323d</guid>
      <description>&lt;p&gt;CaptureOneAI's MCP server had been running for weeks with zero signups coming through it. The cause was dumb in hindsight: the server required an API key for everything, including initialize and tools/list, the methods a client uses to ask what are you and what can you do. Neither reads data or spends quota.&lt;br&gt;
Effect: no MCP directory indexing it, since most of them probe by listing. No agent deciding whether it's worth connecting. No developer evaluating it. A catalog you have to register for before you can read it isn't a catalog.&lt;br&gt;
The fix: a whitelist of description-only methods now answers without a key. tools/call still requires one, so nothing billable is exposed, and the check runs over every message in a batch, so you can't smuggle a tools/call in behind a tools/list. Verified locally: initialize without a key returns 200 and responds, tools/list without a key returns 200 and lists the six tools, tools/call without a key returns 401, and a batch of tools/list plus tools/call without a key also returns 401.&lt;br&gt;
Then we published to the official MCP registry, the one backed by Anthropic, GitHub, PulseMCP and Microsoft, that feeds downstream directories and aggregators. For a remote server there's no package to publish, just metadata plus proof of domain ownership, which meant a namespace matching our domain in reverse and a DNS TXT record before the registry would accept it.&lt;br&gt;
Two papercuts worth remembering for next time. The tool description silently has a 100 character limit the JSON schema doesn't declare (ours was 217, trimmed to 94), and the MCP server's container image doesn't ship curl, so its deploy health check needed to probe from the host instead of inside the container like the other services.&lt;br&gt;
Published: com.captureoneai/web-perception 1.0.0, status active.&lt;br&gt;
captureoneai.com&lt;/p&gt;

</description>
      <category>mcp</category>
      <category>api</category>
      <category>opensource</category>
      <category>ai</category>
    </item>
    <item>
      <title>My AI coding agent already logs my hours. I turned that into a time and AI-cost tracker</title>
      <dc:creator>Jose Daniel Leon Ruiz</dc:creator>
      <pubDate>Wed, 23 Sep 2026 14:00:55 +0000</pubDate>
      <link>https://dev.to/jdevleon/my-ai-coding-agent-already-logs-my-hours-i-turned-that-into-a-time-and-ai-cost-tracker-2hd7</link>
      <guid>https://dev.to/jdevleon/my-ai-coding-agent-already-logs-my-hours-i-turned-that-into-a-time-and-ai-cost-tracker-2hd7</guid>
      <description>&lt;p&gt;If you code with Claude Code, you probably can't answer two simple questions: how many hours did the last feature take, and how much did the AI cost for it?&lt;br&gt;
Time trackers don't help. A stopwatch you have to remember to start always fails, and nobody wants to install something that watches their terminal.&lt;br&gt;
So I built Estela, an open-source CLI that answers both questions from files that already exist on your disk.&lt;/p&gt;

&lt;h2&gt;
  
  
  The idea: read what's already written
&lt;/h2&gt;

&lt;p&gt;Two artifacts already record almost everything you need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Claude Code session files.&lt;/strong&gt; Claude Code saves every session locally, with the model and exact token counts. Estela reads when, how much and with which model. It never stores the content of your prompts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Your git history.&lt;/strong&gt; Estela reads it with git log and matches commits to sessions by timestamp, author and branch. No hooks installed, nothing added to your commit messages. Husky and lefthook stay untouched.
## Measured vs. estimated, never mixed
Not every hour comes from an AI session. If you coded by hand, or with an agent Estela can't read yet (Codex, Cursor, Copilot, Gemini CLI, Aider), your commits are still a trail. Estela infers time from them and labels it as &lt;strong&gt;estimated&lt;/strong&gt;. Hours from Claude Code sessions are labeled &lt;strong&gt;measured&lt;/strong&gt;.
That distinction matters more than it looks: a report is only useful if you know which numbers are real and which are guesses.
## The real cost of AI is not the sum of tokens
If you're on a flat subscription, adding up token prices gives you a number you never paid. Estela prorates your actual subscription across what you consumed, and counts cache separately, because cache is usually the biggest chunk of the bill.
The result: effort per feature, in human hours and in AI money, attributed to the same piece of work.
## A dashboard your client can actually use
Instead of attaching a PDF timesheet, you share a read-only link. Every number drills down to the commits behind it.
And no vanity metrics: no lines of code, no commit counts, no productivity scores. Effort per feature, rewrites, pace and unmerged work.
## Try it
It runs fully local, with no account and no card. The code is open source (MIT) and has zero dependencies. Requires Node 22.5+.
&lt;strong&gt;npx estela setup&lt;/strong&gt;
Then &lt;strong&gt;npx estela web&lt;/strong&gt; opens the dashboard. If you're already in Claude Code, there's also a plugin, and /estela:demo fills a dashboard with fake data so you can see what it does before letting it near your history.
Sample dashboard: &lt;a href="https://getestela.dev/demo" rel="noopener noreferrer"&gt;https://getestela.dev/demo&lt;/a&gt;
Code: &lt;a href="https://github.com/jdleonruiz/estela-cli" rel="noopener noreferrer"&gt;https://github.com/jdleonruiz/estela-cli&lt;/a&gt;
## What I'd love feedback on
Today Estela only reads Claude Code sessions. Which agent should it support next? And if you bill clients for AI-assisted work: how do you handle the AI cost today?&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>claude</category>
      <category>opensource</category>
      <category>productivity</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
