← All writing
Engineering

The AI tax I didn't know I was paying

There's a hidden cost to AI-assisted coding: the tokens you pay for before the model gets to the actual work.

The AI tax I didn't know I was paying
Photo by Bernd 📷 Dittrich / Unsplash

There's a cost to AI-assisted coding that nobody talks about much: the noise.

Not the cost of the model itself — that's obvious. The cost of everything the model has to read before it gets to the actual work. Shell commands padded with usage hints. Git telling you how to use git add before telling you what changed. Test runners printing timing summaries before the failure message you need.

Every one of those tokens costs money. When you're running AI sessions dozens of times a day across multiple tools, it compounds. I spent a few months quietly annoyed before I decided to measure it.


What I found when I measured

A typical git status is 38 tokens. The AI needs 6 — just the changed filenames and their status. Everything else is noise.

BEFORE RTK  (38 tokens)
────────────────────────────────────────────────────
On branch feature/checkout-flow
Your branch is ahead of 'origin/feature/checkout-flow' by 3 commits.
  (use "git push" to publish your local commits)

Changes not staged for commit:
  (use "git add <file>..." to update staging area)
        modified:   src/checkout/ViewCheckout.tsx
        modified:   src/checkout/PresenterCheckout.ts

Untracked files:
        src/checkout/__tests__/ViewCheckout.test.tsx

AFTER RTK  (6 tokens)
────────────────────────────────────────────────────
M  src/checkout/ViewCheckout.tsx
M  src/checkout/PresenterCheckout.ts
?  src/checkout/__tests__/ViewCheckout.test.tsx
Command Raw tokens Filtered Reduction
git status 38 6 84%
jest output ~200 ~40 ~80%
tsc output ~150 ~30 ~80%
Full dev session ~40,000 ~8,000–20,000 50–80%

The tool that produces these numbers is RTK (Rust Token Killer). It rewrites shell commands transparently — the shell runs the full version, the AI sees only the filtered output. No configuration needed.

The output side has the same problem. AI models default to verbose responses:

WITHOUT CAVEMAN  (65 tokens)
────────────────────────────────────────────────────
Sure! After carefully reviewing the code, I can see that there's
actually an issue in the ViewCheckout component. It looks like
there's a useState hook being used directly in the View layer,
which basically violates the EVPMR architecture pattern. You'll
want to move that state logic into the Presenter layer instead.

WITH CAVEMAN  (18 tokens)
────────────────────────────────────────────────────
[ERROR] ViewCheckout.tsx:14 — useState in View layer.
  Why: violates EVPMR.
  Fix: move to PresenterCheckout.ts.
Response type Tokens Reduction
Verbose (default) ~65
Caveman-compressed ~18 72%
Full session impact 40–60%

Caveman is a behavioral rule — a markdown file that loads into every AI session and instructs the model to drop filler without touching technical content. It has three intensity levels (lite, full, ultra) and auto-switches back to full prose for security warnings or sequences where compression would cause ambiguity.


One repo, every tool

After solving the token problem, I ran into the fragmentation problem.

I use four AI coding tools depending on context: Claude Code for most work, Cursor for inline suggestions, Copilot when I'm in a codebase already configured for it, Gemini CLI for specific tasks. Each had drifted into its own version of my workflows. Whenever I improved something in one tool, I forgot to copy it to the others.

agentic-skills solves this with a post-merge hook. After one install, every git pull syncs three namespaces across all four tools:

Namespace Contains Loads
rules/ Always-on behavioral constraints Every session, automatically
skills/ On-demand capabilities When invoked by name or natural language
commands/ Multi-skill workflow orchestrators When invoked by name or natural language

One file change, one push. Everyone has it on next pull. No drift.


The parallel workflow system

Sequential AI workflows are expensive in a specific way: you pay for waiting. Run type checking, wait. Run linting, wait. Run tests, wait. Run a review agent, wait. A full pre-merge check might take ten minutes, most of it idle.

The parallel workflows change the shape of that cost:

"review this"
      ↓
/parallel-review
      ↓
PHASE 1  ─── fast gates, no LLM cost ───────────────
  ├── tsc   ─┐
  ├── lint   ─┼── all run at once
  └── test  ─┘
      ↓ all pass ✓  (any fail → stop, report immediately)
classify diff  ─── reads actual changed files ───────
      ↓
PHASE 2  ─── LLM agents, classifier-selected ────────
  ├── code-quality
  ├── fe-review
  └── fe-a11y?     ← only if View files changed
      ↓
synthesize  ─── merge + deduplicate ─────────────────
      ↓
merged report

Phase 1 is cheap — just command executions, no LLM calls. It runs everything simultaneously. If anything fails, the session ends immediately. No point spending on deep review when the type checker is broken.

Phase 2 only runs if Phase 1 passes, and only spawns agents that make sense for the actual diff:

Changed files Agents spawned Reason
View*.tsx + Presenter*.ts code-quality + fe-review + fe-a11y View has interactive elements
Model*.ts only code-quality Type safety focus, no UI to check
Entry*.tsx or Resource*.ts fe-review only Boundary + string ownership
Test files only None — Phase 2 skipped No production code to review
3+ architecture layers + adversarial agent Large changes carry more hidden risk
Auth / payment paths code-quality (security emphasis) Sensitive paths need extra scrutiny

The test-only case matters most for cost. Zero LLM spend when only tests changed. The adversarial agent has caught things the standard review missed — hidden assumptions, missing edge cases, scope risk that no single-axis review surfaces.


What the rules enforce

The skills are built around a frontend architecture called EVPMR. Every feature is exactly five files with hard layer rules:

Entry      ← ErrorBoundary + context providers
             ALWAYS wrap — no exceptions
     ↓
View       ← pure render only
             NEVER useState / useEffect / API calls
     ↓ (via usePresenter*())
Presenter  ← all hooks, state, React Query
             NEVER return JSX
     ↓
Model      ← TypeScript types + pure functions
             NEVER import React or cause side effects
     ↓
Resource   ← all display strings
             NEVER hardcode text in View

These rules live in fe-rules.md — a markdown file that loads into every session automatically. If your architecture is different, edit the file, push, and every tool has the new rules on next pull. The rules are just text.

The always-active ruleset also includes Karpathy's LLM coding guidelines — adapted into six concrete behaviors: think before coding, simplicity first, surgical changes, goal-driven execution, tests verify intent, checkpoint after every significant step.


Getting started

git clone [email protected]:raditia/agentic-skills.git ~/agentic-skills
cd ~/agentic-skills
bash install.sh

The first sync takes about a minute. Every sync after that is a few seconds on git pull. The repo is public — if you use it, adapt it, or break it in an interesting way, I'd like to hear what you change.


References

raditia
Written by raditia