DEV Community

poowa-gg
poowa-gg

Posted on

I Built a Tool That Turns 40-Year-Old Banking Packets Into Modern APIs — Using Kiro

Every time you tap your card at a terminal, your payment travels through a binary protocol written in 1987.

It's called ISO-8583. Banks run it on IBM mainframes using a character encoding called EBCDIC — invented in 1964. Together, these two technologies process over $10 trillion in daily payment volume. And almost no modern developer can read them.

Today I want to show you how I built AuraGate — a tool that decodes these ancient binary packets and automatically synthesizes a production-ready OpenAPI 3.1 specification and TypeScript SDK from them. And how Kiro made it possible to build something this technically deep in a single hackathon.

🔗 Live app: https://auragate-i1on.vercel.app/
🔗 GitHub: https://github.com/poowa-gg/auragate

The Problem Nobody Talks About

Here is what an ISO-8583 card authorization packet looks like in the wild:

303230301038000000c08000303030303030303135303030343832393130313433303235313130345445524d303030314d45524348414e5430303030303120383430

That is a real payment message. Field 4 is the transaction amount. Field 41 is the terminal ID. Field 49 is the currency code. But you would never know that by looking at it.

Banks pay COBOL consultants $125,000–$197,000 a year just to read and map these fields. The average COBOL developer is now above 55 years old. Fewer than 1% of computer science graduates study COBOL today. The skills cliff is accelerating at 10% per year.

Every fintech that wants to integrate with a bank, every payment processor building modern infrastructure, every developer trying to understand what their legacy system is actually sending — they all hit the same wall.

I wanted to demolish that wall.

What AuraGate Does

Drop in a raw hex payload. AuraGate gives you back:

  1. Decoded JSON — every field named and typed:

json
{
  "mti": "0200",
  "fields": {
    "4": "000000015000",
    "11": "482910",
    "41": "TERM0001",
    "49": "840"
  },
  "presentFields": [4, 11, 41, 49]
}

2. A valid OpenAPI 3.1 specification — ready for Postman, Swagger UI, or AWS API Gateway:

{
  "openapi": "3.1.0",
  "info": { "title": "PaymentSwitchV1", "version": "1.0.0" },
  "paths": {
    "/api/v1/transactions/process": { ... }
  },
  "components": {
    "schemas": {
      "TransactionPayload": {
        "properties": {
          "amount": { "type": "number", "example": 150.00 },
          "terminalId": { "type": "string", "example": "TERM0001" }
        }
      }
    }
  }
}

3. A TypeScript interface — ready to paste into your microservice:

export interface TransactionPayload {
  mti: '0200';
  amount?: number;
  stan?: number;
  terminalId?: string;
  currencyCode?: number;
}

_What would take a COBOL consultant 3–6 months to document just happened in under a second._

**How I Built It With Kiro**

This is where it gets interesting. I didn't just use Kiro as a code autocomplete tool. I used it the way it was designed to be used — spec-first, with steering, hooks, and MCP.

1. Spec-Driven Development
Before writing a single line of code, I opened Kiro and created a spec.


2. Requirements.md
 I defined 7 requirement groups — codecs, error handling, PBT invariants, synthesis engine, MCP server. Then tasks.md organized them into a 5-wave dependency graph:

{
  "waves": [
    { "id": 1, "description": "Environment setup", "tasks": ["1"] },
    { "id": 2, "description": "Binary codecs", "tasks": ["2", "4"] },
    { "id": 3, "description": "Property-based tests", "tasks": ["3", "5"] },
    { "id": 4, "description": "OpenAPI synthesizer", "tasks": ["6"] },
    { "id": 5, "description": "MCP server", "tasks": ["7"] }
  ]
}

Kiro read the spec and implemented each wave in the correct dependency order — without me micromanaging sequencing. The codecs came out correct on the first pass because the spec forced the right design constraints upfront.

This is the single biggest shift in how I code now. Writing requirements before code forces clarity that prevents entire classes of bugs.

3. Steering Docs as Architecture Guardrails
I created architecture.md with hard rules 

A) Zero-copy byte parsing only — Buffer.subarray, never string slicing.
B) Every decoder returns Result<T, ParseError> — never throws.
C No any types anywhere.
D) PBT required for every codec module.

Kiro respected these rules across every file it generated. I never had to say "don't use string slicing" in chat — it was already in the steering doc. This is the difference between vibe coding and disciplined AI-assisted engineering.

4. MCP — The Feature That Changed Everything
I built an MCP server that extends Kiro's own agent with three tools:

// Callable directly from Kiro chat:
inspect_iso8583_stream({ payload: "303230301038..." })
inspect_ebcdic_stream({ payload: "c1e4d9c1c7..." })
synthesize_microservice({ payload: "303230301038...", serviceName: "CardAuthV2" })

inspect_iso8583_stream, and see the decoded fields inline in my IDE — no browser, no terminal switch, no context break. This collapsed the test-and-verify loop from minutes to seconds.

MCP turns AuraGate from a standalone tool into a permanent fixture in an AI-assisted developer workflow. That's the real modernization story.

5. Hooks — Automated Verification on Every Save
I added a PostFileSave hook in 
test-on-save.json that automatically runs the full property-based test suite whenever any .ts file is saved.

Every codec edit is instantly verified against 7,000 test assertions without any manual npm test. When you're working on byte-level parsing, this kind of continuous safety net is not a nice-to-have — it is essential.

6. The Vibe Coding That Started It All
The architecture emerged from a single Kiro chat conversation. I described the problem domain — "I need to parse ISO-8583 binary packets and generate OpenAPI specs". Kiro proposed:

The Result<T, ParseError> discriminated union pattern
The 5-wave task dependency graph
fast-check for property-based testing
Zero-copy Buffer.subarray parsing
A blank repo became a complete, typed architecture plan in under 10 minutes. Then the spec locked it in. Then the steering docs enforced it. Then Kiro implemented it.

**The Technical Core**
_Zero-Copy Binary Parsing_

Every byte range is operated on via typed views:

// Never do this:
const field = buffer.toString('utf-8').slice(offset, offset + length)

// AuraGate does this:
const field = buffer.subarray(offset, offset + length).toString('utf-8')


The difference: zero intermediate string allocations. For a tool that handles real payment packets, memory efficiency is not optional.

The Result Type — Never Throw
Every decoder returns a discriminated union:

export type Result<T, E = ParseError> =
  | { success: true;  value: T }
  | { success: false; error: E }

In a payments context, an uncaught exception means a failed transaction. The Result type makes failure a first-class typed value that every caller must handle at compile time — not a runtime surprise.

**Property-Based Testing**
Example-based tests would never find all the edge cases in a 128-bit bitmap parser. fast-check generates 1,000 random inputs per invariant:

// Round-trip invariant: decode(encode(M)) === M
fc.assert(
  fc.property(fc.integer({ min: -9999999, max: 9999999 }), (val) => {
    const packed   = encodeComp3(val, 4, 0)
    const unpacked = decodeComp3(packed, 0)
    assert.equal(unpacked.success, true)
    if (unpacked.success) assert.equal(unpacked.value, val)
  }),
  { numRuns: 1000 }
)


10 tests. 10 passing. 0 failing. 7,000 total assertions.

Try It Yourself
The fastest way to see AuraGate work:

Open https://auragate-i1on.vercel.app/                                

The ISO-8583 tab pre-loads a real 0200 authorization packet
Click Unpack Fields — see every field decoded
Click OpenAPI Synthesizer → paste the same hex → click Synthesize
Watch a valid OpenAPI 3.1 spec appear from raw binary

Or hit the API directly:

curl -X POST https://auragate.vercel.app/api/v1/bridge/synthesize \
  -H "Content-Type: application/json" \
  -d '{
    "payload": "303230301038000000c08000303030303030303135303030343832393130313433303235313130345445524d303030314d45524348414e5430303030303120383430",
    "serviceName": "CardAuthV2"
  }'


What's Next

SWIFT MT + ISO-20022 support — bridging the ISO-8583 to ISO-20022 migration gap
Hosted SaaS — team dashboards, saved decode history, CI/CD plugin
GitHub Actions step — fail a build if your wire format changed unexpectedly
NACHA ACH decoder — $80 trillion/year in US ACH transactions, still flat COBOL files

**The mainframe modernisation market is $8 billion today, growing to $18.42  billion by 2034. COBOL developers are disappearing. AuraGate's value increases every single year.**

Final Thought

Kiro did not just help me write code faster. It changed how I build things. Spec-driven development with steering docs and property-based testing is a fundamentally more reliable way to produce correct software — especially for something as unforgiving as binary protocol parsing.

If you work anywhere near legacy financial systems, AuraGate was built for you. Drop in a packet. Walk out with an API.

🔗 Live: https://auragate-i1on.vercel.app/  🔗 Code: https://github.com/poowa-gg/auragate

Built for Kiroween 2026 — Resurrection Category — with Kiro

#KiroweenHackathon26


Enter fullscreen mode Exit fullscreen mode

Top comments (0)