<?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>Forem: Soumya Prasad</title>
    <description>The latest articles on Forem by Soumya Prasad (@soumyaprasadrana).</description>
    <link>https://forem.com/soumyaprasadrana</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%2F2396034%2Faf221698-da95-4030-8a62-f51a730b4489.jpg</url>
      <title>Forem: Soumya Prasad</title>
      <link>https://forem.com/soumyaprasadrana</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/soumyaprasadrana"/>
    <language>en</language>
    <item>
      <title>Stop Bleeding Tokens: How We Cut Enterprise API Costs by 46% with a Lossless JSON Encoder</title>
      <dc:creator>Soumya Prasad</dc:creator>
      <pubDate>Sat, 28 Feb 2026 18:26:07 +0000</pubDate>
      <link>https://forem.com/soumyaprasadrana/stop-bleeding-tokens-how-we-cut-enterprise-api-costs-by-46-with-a-lossless-json-encoder-4ol5</link>
      <guid>https://forem.com/soumyaprasadrana/stop-bleeding-tokens-how-we-cut-enterprise-api-costs-by-46-with-a-lossless-json-encoder-4ol5</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;You're not paying for what your LLM thinks. You're paying for what your enterprise API sends.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  The Token Crisis Nobody Talks About
&lt;/h2&gt;

&lt;p&gt;Everyone talks about prompt engineering, context windows, and model selection when optimizing LLM costs. But there's a silent killer hiding in plain sight — &lt;strong&gt;the raw JSON payloads from enterprise APIs&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;When you connect an AI agent to systems like IBM Maximo, ServiceNow, or SAP, you're not just getting data back. You're getting &lt;em&gt;infrastructure noise&lt;/em&gt; dressed up as data.&lt;/p&gt;

&lt;p&gt;Here's what a &lt;strong&gt;single&lt;/strong&gt; incident record from a Maximo OSLC API actually looks like:&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"owner"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"PRIYA.N"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"status_description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"In Progress"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"slarecords_collectionref"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"api/os/mxapiincident/_VElDS0VULzEwMDE3Mw--/slarecords"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"labtrans_collectionref"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="s2"&gt;"api/os/mxapiincident/_VElDS0VULzEwMDE3Mw--/labtrans"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"ticketprop_collectionref"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"api/os/mxapiincident/_VElDS0VULzEwMDE3Mw--/ticketprop"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"relatedrecord_collectionref"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"api/os/mxapiincident/_VElDS0VULzEwMDE3Mw--/relatedrecord"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"_rowstamp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"26338737"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"accumulatedholdtime"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"class_description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Service Request"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"class"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"SR"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"changeby"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"PRIYA.N"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"createdby"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"MAXUSER1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"ownergroup"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"PLANTOPS"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"origfromalert"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's &lt;strong&gt;one&lt;/strong&gt; record. Now multiply it by 15–20 records per page. The pattern becomes painfully clear:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;slarecords_collectionref&lt;/code&gt;, &lt;code&gt;labtrans_collectionref&lt;/code&gt;, &lt;code&gt;ticketprop_collectionref&lt;/code&gt; — pagination handles the LLM &lt;strong&gt;can never call&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;_rowstamp&lt;/code&gt; — a database concurrency token the LLM has no use for&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;PRIYA.N&lt;/code&gt;, &lt;code&gt;SR&lt;/code&gt;, &lt;code&gt;MAXUSER1&lt;/code&gt;, &lt;code&gt;PLANTOPS&lt;/code&gt; — repeated &lt;strong&gt;identically&lt;/strong&gt; across every single record&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;class_description: "\"Service Request\"&lt;/code&gt; alongside &lt;code&gt;class: \"SR\"&lt;/code&gt; — the same thing, twice, on every row"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On a real-world test of 15 Maximo incident records: &lt;strong&gt;~5,400 tokens consumed&lt;/strong&gt;. The LLM asked for incident data. It got database plumbing.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Insight: Enterprise APIs Weren't Built for LLMs
&lt;/h2&gt;

&lt;p&gt;Enterprise systems like Maximo were designed for browser UIs and system integrations — not token-efficient AI consumption. Their REST/OSLC APIs are built to be complete and self-describing. That's great for a UI developer. It's expensive for an LLM.&lt;/p&gt;

&lt;p&gt;The data your agent actually needs is maybe &lt;strong&gt;40–50% of what gets sent&lt;/strong&gt;. The rest is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Repeated strings&lt;/strong&gt; — owner names, status codes, class labels duplicated on every record&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Collection refs&lt;/strong&gt; — internal pagination handles the LLM can't follow&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Internal metadata&lt;/strong&gt; — rowstamps, localrefs, origfromalert flags&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Verbose field names&lt;/strong&gt; — &lt;code&gt;description_longdescription&lt;/code&gt;, &lt;code&gt;status_description&lt;/code&gt;, &lt;code&gt;class_description&lt;/code&gt; eating characters&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;HTML markup&lt;/strong&gt; — embedded in long description fields, consuming tokens on angle brackets&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every token of this noise costs money. On high-frequency agentic workflows — think a help desk AI processing hundreds of incident queries per hour — this adds up fast.&lt;/p&gt;




&lt;h2&gt;
  
  
  Introducing &lt;code&gt;lean-normalizer&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;We built &lt;a href="https://github.com/soumyaprasadrana/lean-normalizer" rel="noopener noreferrer"&gt;&lt;code&gt;lean-normalizer&lt;/code&gt;&lt;/a&gt; — a pre-processing layer that sits between your enterprise API and your LLM tool call. It encodes the response into &lt;strong&gt;LEAN format&lt;/strong&gt;: a compact, human-readable, fully reversible wire format specifically designed for LLM consumption.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;LEAN&lt;/strong&gt; stands for &lt;strong&gt;L&lt;/strong&gt;ossless &lt;strong&gt;E&lt;/strong&gt;nterprise &lt;strong&gt;A&lt;/strong&gt;PI &lt;strong&gt;N&lt;/strong&gt;ormalization.&lt;/p&gt;

&lt;p&gt;The key word is &lt;strong&gt;lossless&lt;/strong&gt;. Nothing is dropped. Every field value is preserved. The LLM can reconstruct any original value without any client-side code.&lt;/p&gt;

&lt;h3&gt;
  
  
  What It Does
&lt;/h3&gt;

&lt;p&gt;LEAN encoding applies three compression strategies in two passes:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Dictionary deduplication&lt;/strong&gt;&lt;br&gt;
Any string that repeats across records gets stored once in a &lt;code&gt;### DICT&lt;/code&gt; block and referenced as a &lt;code&gt;*N&lt;/code&gt; pointer inline. &lt;code&gt;PRIYA.N&lt;/code&gt; appearing 13 times across 15 records? Stored once. Referenced as &lt;code&gt;*0&lt;/code&gt; everywhere else.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Schema key shortening&lt;/strong&gt;&lt;br&gt;
Long field names like &lt;code&gt;status_description&lt;/code&gt;, &lt;code&gt;description_longdescription&lt;/code&gt;, &lt;code&gt;accumulatedholdtime&lt;/code&gt; get replaced with short base-36 keys (&lt;code&gt;d&lt;/code&gt;, &lt;code&gt;i&lt;/code&gt;, &lt;code&gt;0&lt;/code&gt;). The mapping lives in a &lt;code&gt;### SCHEMA&lt;/code&gt; block the LLM reads once.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Noise suppression&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;_rowstamp&lt;/code&gt;, &lt;code&gt;*_collectionref&lt;/code&gt; fields, &lt;code&gt;localref&lt;/code&gt;, empty strings, HTML markup — stripped entirely via adapter-specific rules. The LLM never asked for them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Two things are never compressed:&lt;/strong&gt; &lt;code&gt;href&lt;/code&gt; values and ISO dates. These are always emitted raw so agents can pass them directly to follow-up tool calls (&lt;code&gt;PATCH&lt;/code&gt;, &lt;code&gt;GET&lt;/code&gt;) without any decoding step.&lt;/p&gt;
&lt;h3&gt;
  
  
  The Output Format
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;### LEAN FORMAT v1

### DICT
*0=PRIYA.N
*1=SR
*2=Service Request
*3=MAXUSER1
*4=QUEUED

### SCHEMA
0=accumulatedholdtime
1=changeby
c=status
d=status_description
f=ticketid
h=description
i=description_longdescription

### DATA: member
_id:0 0:0 1:"*0" 3:"*1" 4:"*2" 5:"*3" c:"*4" d:"Queued" f:100171 ...
_id:1 0:0 1:"*0" 3:"*1" 4:"*2" 5:"*3" h:"High Priority: Cooling Tower..." c:"*9" ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The LLM reads &lt;code&gt;### SCHEMA&lt;/code&gt; and &lt;code&gt;### DICT&lt;/code&gt; once, then processes each &lt;code&gt;### DATA&lt;/code&gt; row. Nested child objects (like &lt;code&gt;relatedrecord&lt;/code&gt; arrays) are decomposed into named child tables linked by &lt;code&gt;_p&lt;/code&gt; parent references — flat, indexed, readable.&lt;/p&gt;


&lt;h2&gt;
  
  
  Real-World Test Results
&lt;/h2&gt;

&lt;p&gt;We tested against a real IBM Maximo instance, querying active incidents via the &lt;code&gt;MXAPIINCIDENT&lt;/code&gt; OSLC Object Structure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dataset:&lt;/strong&gt; 13 incident records, full &lt;code&gt;oslc.select=*&lt;/code&gt; payload including doclinks and related records.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Mode&lt;/th&gt;
&lt;th&gt;Payload Size&lt;/th&gt;
&lt;th&gt;Tokens (approx)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Raw JSON (&lt;code&gt;useLean=false&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;18,407 chars&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;~4,600&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LEAN encoded (&lt;code&gt;useLean=true&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;9,921 chars&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;~2,480&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Saving&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;8,486 chars&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;~2,120 tokens (~46%)&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Compression ratio: 0.539&lt;/strong&gt; — consistently in the 46–54% range across multiple runs on the same dataset.&lt;/p&gt;

&lt;p&gt;The circuit breaker was not triggered (it fires only when encoding would make the payload &lt;em&gt;larger&lt;/em&gt;, which can happen with very small or highly unique datasets).&lt;/p&gt;
&lt;h3&gt;
  
  
  Was Any Data Lost?
&lt;/h3&gt;

&lt;p&gt;We cross-validated both responses field by field:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;All 13 records returned in both modes ✅&lt;/li&gt;
&lt;li&gt;All ticket IDs, descriptions, priorities, statuses matched ✅&lt;/li&gt;
&lt;li&gt;Related records and linked work orders preserved ✅&lt;/li&gt;
&lt;li&gt;Attachment/doclink metadata intact ✅&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;actualfinish&lt;/code&gt; dates on resolved tickets present in both ✅&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Zero data loss. 46% token reduction.&lt;/strong&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  LLM Compatibility
&lt;/h2&gt;

&lt;p&gt;A natural question: can modern LLMs actually decode this format reliably?&lt;/p&gt;

&lt;p&gt;We tested with &lt;strong&gt;Claude (Anthropic)&lt;/strong&gt; and &lt;strong&gt;OpenAI&lt;/strong&gt; tool calling. Both models handle LEAN decoding correctly — they read &lt;code&gt;### SCHEMA&lt;/code&gt; to resolve short keys, read &lt;code&gt;### DICT&lt;/code&gt; to expand &lt;code&gt;*N&lt;/code&gt; pointers, and process &lt;code&gt;### DATA&lt;/code&gt; rows without confusion.&lt;/p&gt;

&lt;p&gt;The format is intentionally designed to be self-documenting. There's no magic — it's structured text with a two-block header. Any enterprise-grade LLM that can follow instructions can decode it. The tool description tells the model the format exists upfront:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Returns open Maximo incidents. When the response contains "### LEAN FORMAT v1", &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;it is LEAN-encoded. Use ### SCHEMA to map short keys back to field names, &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;and ### DICT to expand *N pointer values. &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;href values and ISO dates are always emitted raw.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's all the LLM needs. No client SDK. No parsing library on the model side.&lt;/p&gt;




&lt;h2&gt;
  
  
  Using It in Your MCP Tool
&lt;/h2&gt;

&lt;p&gt;Installation is a single package:&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; @soumyaprasadrana/lean-normalizer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Drop it into any MCP tool that retrieves enterprise data:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;LeanEncoder&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;MaximoAdapter&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@soumyaprasadrana/lean-normalizer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;encoder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;LeanEncoder&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;adapter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MaximoAdapter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;tool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;get_incidents&lt;/span&gt;&lt;span class="dl"&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="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;raw&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;maximo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getIncidents&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;encoder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;encoded&lt;/span&gt; &lt;span class="p"&gt;}],&lt;/span&gt;
    &lt;span class="na"&gt;_meta&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;lean_compressed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;     &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;compressed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;lean_ratio&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;          &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ratio&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;lean_original_bytes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;originalSize&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;lean_encoded_bytes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;encodedSize&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;_meta&lt;/code&gt; block is optional but useful for monitoring compression stats in tool call traces.&lt;/p&gt;

&lt;p&gt;The circuit breaker handles edge cases automatically — if encoding a small payload would make it &lt;em&gt;larger&lt;/em&gt;, the library returns raw JSON unchanged with &lt;code&gt;compressed: false&lt;/code&gt;. Your agent code doesn't need to handle this specially.&lt;/p&gt;




&lt;h2&gt;
  
  
  Built-in Adapters
&lt;/h2&gt;

&lt;p&gt;The library ships adapters for three enterprise systems out of the box:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;IBM Maximo (OSLC / REST API)&lt;/strong&gt;&lt;br&gt;
Detects the root array at &lt;code&gt;payload.member&lt;/code&gt;, derives table names from OSLC Object Structure hrefs, suppresses &lt;code&gt;_rowstamp&lt;/code&gt; / &lt;code&gt;*_collectionref&lt;/code&gt; fields, strips &lt;code&gt;spi:&lt;/code&gt; / &lt;code&gt;rdf:&lt;/code&gt; namespace prefixes, strips HTML from long descriptions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ServiceNow (Table API)&lt;/strong&gt;&lt;br&gt;
Detects root at &lt;code&gt;payload.result&lt;/code&gt;, drops the &lt;code&gt;link&lt;/code&gt; half of reference objects (&lt;code&gt;{ link, value }&lt;/code&gt; → keeps &lt;code&gt;value&lt;/code&gt;), suppresses &lt;code&gt;sys_class_name&lt;/code&gt;, &lt;code&gt;sys_domain&lt;/code&gt;, &lt;code&gt;sys_domain_path&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SAP OData (v2 and v4)&lt;/strong&gt;&lt;br&gt;
Detects root at &lt;code&gt;payload.d.results&lt;/code&gt; or &lt;code&gt;payload.value&lt;/code&gt;, strips &lt;code&gt;__metadata&lt;/code&gt; and &lt;code&gt;__deferred&lt;/code&gt;, converts &lt;code&gt;/Date(ms)/&lt;/code&gt; timestamps to ISO-8601.&lt;/p&gt;

&lt;p&gt;Writing a new adapter is ~30 lines of TypeScript — implement the &lt;code&gt;LeanAdapter&lt;/code&gt; interface, add a fixture JSON, add a test.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Economics
&lt;/h2&gt;

&lt;p&gt;Let's make this concrete. Suppose your AI agent processes &lt;strong&gt;500 Maximo incident queries per day&lt;/strong&gt; — a moderate load for a help desk automation.&lt;/p&gt;

&lt;p&gt;At ~4,600 tokens per raw query vs ~2,480 tokens with LEAN:&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;Raw JSON&lt;/th&gt;
&lt;th&gt;LEAN&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Tokens per query&lt;/td&gt;
&lt;td&gt;~4,600&lt;/td&gt;
&lt;td&gt;~2,480&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Daily tokens (500 queries)&lt;/td&gt;
&lt;td&gt;~2,300,000&lt;/td&gt;
&lt;td&gt;~1,240,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Daily saving&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;~1,060,000 tokens&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;At typical enterprise LLM pricing, that's a meaningful cost line — and it compounds directly with query volume. The heavier your agentic workload, the more LEAN pays for itself.&lt;/p&gt;

&lt;p&gt;And this is just the input token side. Smaller context also means faster responses — the model processes less before it can start reasoning.&lt;/p&gt;




&lt;h2&gt;
  
  
  When to Use It (and When Not To)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Good fit:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;MCP tools connecting to Maximo, ServiceNow, SAP&lt;/li&gt;
&lt;li&gt;Any enterprise API that returns repetitive, field-heavy records&lt;/li&gt;
&lt;li&gt;Agentic workflows with high query volume&lt;/li&gt;
&lt;li&gt;Situations where you're approaching context window limits&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Not the right tool:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Very small payloads (1–3 records) — the circuit breaker will likely return raw JSON anyway&lt;/li&gt;
&lt;li&gt;Streaming responses — LEAN is a complete-payload format&lt;/li&gt;
&lt;li&gt;Cases where the LLM needs raw JSON for downstream tool arguments (though &lt;code&gt;href&lt;/code&gt; and dates are always raw)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;p&gt;The library is experimental and actively maintained. A few things on the roadmap:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Selective field encoding&lt;/strong&gt; — let adapters specify which fields are agent-critical vs suppressible, giving finer control than the current skip/keep binary&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Streaming-safe chunked mode&lt;/strong&gt; — for APIs that support server-sent events&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;More adapters&lt;/strong&gt; — Oracle EBS, Salesforce, Dynamics 365 are obvious next targets&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Benchmarks dashboard&lt;/strong&gt; — a public comparison of compression ratios across different enterprise API response shapes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Contributions are welcome. If you're connecting an AI agent to any enterprise system and hitting token ceilings, this library might be worth a look.&lt;/p&gt;




&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;📦 &lt;strong&gt;npm:&lt;/strong&gt; &lt;a href="https://www.npmjs.com/package/@soumyaprasadrana/lean-normalizer" rel="noopener noreferrer"&gt;npmjs.com/package/@soumyaprasadrana/lean-normalizer&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;💻 &lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/soumyaprasadrana/lean-normalizer" rel="noopener noreferrer"&gt;github.com/soumyaprasadrana/lean-normalizer&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Built while wiring up an IBM Maximo incident planning agent. The token bills were the motivation. The 46% reduction was the result.&lt;/em&gt;&lt;/p&gt;




</description>
      <category>ai</category>
      <category>encoder</category>
      <category>mcp</category>
      <category>maximo</category>
    </item>
    <item>
      <title>Supercharge Java Debugging in VS Code with Java DebugX: Macro Recording &amp; Playback Made Easy</title>
      <dc:creator>Soumya Prasad</dc:creator>
      <pubDate>Sun, 10 Nov 2024 03:54:20 +0000</pubDate>
      <link>https://forem.com/soumyaprasadrana/supercharge-java-debugging-in-vs-code-with-java-debugx-macro-recording-playback-made-easy-57kl</link>
      <guid>https://forem.com/soumyaprasadrana/supercharge-java-debugging-in-vs-code-with-java-debugx-macro-recording-playback-made-easy-57kl</guid>
      <description>&lt;p&gt;Let’s face it: if you’re a developer, a massive chunk of your time is probably spent on debugging. While development might only take up 20% of the process, the rest is usually about fixing issues, tracing paths, and reproducing bugs. Debugging large Java applications can be especially challenging and time-consuming, as you sift through complex flows and repeatedly retrace steps. But what if there was a way to make this easier?&lt;/p&gt;

&lt;p&gt;Meet &lt;strong&gt;Java DebugX&lt;/strong&gt;—an innovative Visual Studio Code extension designed to transform Java debugging with advanced features like macro recording and automated playback. Let’s dive into how Java DebugX can simplify the debugging process, saving you time and increasing productivity.&lt;/p&gt;

&lt;h4&gt;
  
  
  Setting Up Java DebugX in VS Code
&lt;/h4&gt;

&lt;p&gt;To get started, ensure you have Visual Studio Code set up with the &lt;strong&gt;Red Hat Java Language Support&lt;/strong&gt; and &lt;strong&gt;Lightweight Java Debugger&lt;/strong&gt; extensions installed. These provide essential Java development and debugging support in VS Code.&lt;/p&gt;

&lt;p&gt;Then, install &lt;strong&gt;Java DebugX&lt;/strong&gt; from the marketplace. It’s as simple as searching for "Java DebugX" in the Extensions tab and clicking install. With Java DebugX, you’re ready to take debugging to a new level.&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%2Fdz4sy2svz8kmh4z12hjz.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%2Fdz4sy2svz8kmh4z12hjz.png" alt="DebugXInMarketplace" width="800" height="279"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Recording a Debugging Session with Java DebugX
&lt;/h4&gt;

&lt;p&gt;Once installed, you’ll see a "Start Recording" button in the &lt;strong&gt;Stack View&lt;/strong&gt; navigation menu. Start a debugging session as usual and press "Start Recording." Java DebugX will automatically record your actions, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Step in, step out, and step over actions&lt;/li&gt;
&lt;li&gt;Setting and removing breakpoints&lt;/li&gt;
&lt;li&gt;Continue and pause actions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every action is saved in a macro format, allowing you to replay the session later. This can be invaluable if you’re debugging a complex flow and need to reproduce the exact sequence of actions without repeating each step manually.&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%2Fzt6g8agvuk8zp9d9k8ed.gif" 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%2Fzt6g8agvuk8zp9d9k8ed.gif" alt="MacroRecord" width="800" height="425"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h5&gt;
  
  
  Macro Recording Action Buttons
&lt;/h5&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%2F7mdh7kqmwv9n5l4d83yq.gif" 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%2F7mdh7kqmwv9n5l4d83yq.gif" alt="MacroRecordActionButtons" width="548" height="262"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Playing Back the Recorded Macro
&lt;/h4&gt;

&lt;p&gt;After recording, you can play back the macro to revisit the debugging flow starting from the exact breakpoint where you initially began recording. Java DebugX allows you to control playback speed by setting &lt;code&gt;java.debugx.macro.stepDelayInSeconds&lt;/code&gt;, adding delays between each automated playback step. Additionally, you can pause, resume, or stop the playback anytime using buttons in the &lt;strong&gt;Stacktrace Navigation Menu&lt;/strong&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Play a macro
&lt;/h4&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%2F79li121n52nwbbl4w08z.gif" 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%2F79li121n52nwbbl4w08z.gif" alt="MacroPlayback" width="800" height="425"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  How playback works
&lt;/h4&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%2F7f19x0ywd85xobbaz85o.gif" 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%2F7f19x0ywd85xobbaz85o.gif" alt="Playback" width="800" height="425"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Playback actions
&lt;/h4&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%2Fncw66rumn859g4p3i2ij.gif" 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%2Fncw66rumn859g4p3i2ij.gif" alt="PlaybackActions" width="517" height="402"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  How Java DebugX Can Boost Productivity
&lt;/h4&gt;

&lt;p&gt;Here’s a typical scenario: You’re debugging a large Java application and find a potential root cause. But after stepping forward, you realize you need to repeat the process to verify something. In a real-life setting, this is where Java DebugX shines—you can record the session once, then replay it up to the exact point you need to examine again.&lt;/p&gt;

&lt;p&gt;Java DebugX even includes enhanced diagnostics to help when your macro takes a wrong path. If your playback reaches a point that differs from the expected line (like reaching an unexpected catch block or exception), DebugX will try to gather diagnostics and log them to a file, giving you a better understanding of potential issues.&lt;/p&gt;

&lt;h4&gt;
  
  
  Transforming Java Debugging with Java DebugX
&lt;/h4&gt;

&lt;p&gt;With Java DebugX, debugging becomes faster, more manageable, and much less repetitive. This extension helps reduce human error and time spent on manual tasks, letting you focus on what matters—finding and fixing issues efficiently.&lt;/p&gt;

&lt;p&gt;Install Java DebugX today and see how it can change the way you debug!``&lt;/p&gt;

&lt;h4&gt;
  
  
  Explore Java DebugX on GitHub
&lt;/h4&gt;

&lt;p&gt;Java DebugX is an open-source project, and you can find the complete codebase, documentation, and updates on its &lt;a href="https://github.com/soumyaprasadrana/vscode-java-debugx" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Whether you’re curious about how it’s built, want to contribute, or need to report an issue, the GitHub repo has everything you need. Join our community of developers and help make Java debugging even better!&lt;/p&gt;

</description>
      <category>java</category>
      <category>vscode</category>
      <category>automation</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
