Plain tool call
Every attempt reaches the payment provider.
REFUNDED
Waiting for the agent.
Lead backend engineer, now building end to end / Lahore / Ten years in production
An AI agent can now refund your customer, and retry when the network blinks. I spent ten years making production systems behave. Now I build whole products by directing agents in plain English, with the safety rails to know exactly what happened.
01 / The bug of this decade
Agents time out, crash, resume and try again. You can't fix that by asking the model to be careful. The fix has to live below the tool call, in something that remembers. Go on, be the flaky network.
refund(charge: "ch_123", amount: "$50.00")
Every attempt reaches the payment provider.
REFUNDED
Waiting for the agent.
Irreversible, so it waits for a person. Key …
Agent wants to refund $50.00. You're the human in the loop.
REFUNDED
Waiting for the agent.
Each row's SHA-256 covers the row before it, computed live in your browser. Change history and everything after it stops verifying.
No events yet.
A browser simulation of how Airlock behaves; the hashes are real. The SDK itself is one pip install airlock-sdk away: v0.3.0, MIT, on GitHub. Why I built it: The double refund. That was a simulation. The real thing runs on this server: sign the ledger at the end ↓
02 / The stack
Ten years, and more than 40 Rails apps carrying my code. Keep scrolling and the career builds itself. The tower is borrowed from Stack Drop, my first game.
First job, at PlumZ Studios: Android apps and the APIs behind them. I wanted to know what was on the other side of the request, and I still do.
Three promotions in four and a half years, leading backend and Android for startups: Roomer Travel, FoneWire, Zilker's IoT irrigation, Modern Advisor, Crema.co. Every domain had its own way to fail in production.
My own shop for freelance Rails work: ServiceLovers, LoopCom, The Test Request. Owning the client and the invoice as well as the code changes how you estimate.
"Create & publish your first Ruby gem" at RubyConf Pakistan. By July 2022 I was managing the community, and I still am.
Senior roles at Nextbridge and InvoZone. A Ruby SDK and Puppet plugin for RevBits PAM, and FreshPrep's meal-kit platform: systems where a mistake reaches someone's secrets, or their dinner.
Lead backend engineer on the Rails monolith behind reservations, loyalty and guest data for thousands of restaurants in 15+ countries. 6,700+ commits. If a retry books a table twice, a real family is standing at the door.
Spoke on building 10x faster Rails apps at the Global Ruby on Rails Summit. Started using Copilot the same year, which turned out to be the first rung of a long ladder.
Ruby on Rails for Agile Web Development, published by AVA. Nothing exposes what you don't understand like explaining it to strangers in print.
Masosa, in Sheikhupura. Eight months preparing an empty shop, then the first customer. After years of writing software for restaurants, I stood on the other side of the counter.
Wapas in March. Agent-driven bug fixing at work from April. An agent running on its own VPS. Airlock in July. Then ten games in 48 days, September to October. This is the block I'm standing on now.
03 / The range
Restaurants are where I went deepest, not the only place I've been. Ten years of work has taken me from payments to smart irrigation, and every domain fails in its own way.
Underneath all of it: Rails, PostgreSQL, Redis, Android, AWS, running my own VPS servers with Docker and nginx, and now AI agents.
04 / The loop
Of everything above, this is the one I own end to end. It isn't four side projects. It's one loop, and I own every station on it. It's why I think about software in terms of who gets hurt when it's wrong.
By day: UMAI runs bookings for thousands of restaurants.
Masosa: my own restaurant, my own Friday-night rush, my own payroll.
Wapas: most first-time customers never return, so I built stamp cards with no app to install. "Wapas" means "back".
Stack Drop: a tower game on every table, with real prizes from the kitchen. Which brings people back to #2.
05 / How I work with agents
For ten years I went deep on the backend: data, money, retries, the parts that can't fail. With agents writing most of the code, that depth now reaches the whole product. I design the screens, build the frontend, wire the APIs and ship to web, Android and TV, end to end.
"Refund the customer if the order failed."
The agent times out, retries and refunds twice. Nobody told it what counts as done.
"Refund once per charge. If you can't tell whether it went through, check before trying again. Anything over $50 waits for a person."
One refund, one approval, and one record you can audit.
Why the backend years count even more now: English compiles a vague sentence into confident, wrong software. I know what to specify because I've seen what breaks when nobody does, so the frontend I ship holds up as well as the backend under it.
At work / team-wide
A pipeline where agents take a bug ticket to a tested pull request, across a Rails backend, four web frontends and an iOS app. One fix can span several codebases, with a merge order.
How it works ↓At work / stack-wide
Agents review the team's pull requests, backend and frontend, against review standards I wrote. They check the risky parts first, like migrations and authorization, and they've caught real bugs before release.
Side lab / since September 2026
My test bed for how far directing agents can go. It started as ten games in 48 days, and it keeps shipping, phone to TV.
See the studio →At work / since April 2026
QA marks a bug ticket, and agents do the work between that and a pull request. It began as an experiment, and its fixes now run in production. It has taught me more about directing agents than anything else I've built.
Reads the ticket and the code across every codebase, decides whether it's really a bug, then writes an ordered plan with the core fix first.
Makes the change on its own branch, adds a regression test and opens a pull request.
A second agent attacks the fix, looking for reasons it doesn't solve the ticket, and sends it back.
The team's own CI runs the tests rather than trusting the agent. A red build gets a capped number of retries.
Then three people: a developer reviews it, QA tests it on staging, and someone approves the merge. Those gates aren't a stopgap until the models improve. They're the design.
06 / Where this goes
Idempotency used to be a payments-team concern. Once every tool call can come from a model that retries, it's everyone's concern, and it belongs in infrastructure.
The double refundWhen code gets cheap, judgment gets expensive. The senior engineer's job becomes knowing what's wrong with something that looks right.
Let's talk about reading itAgents thrive on conventions and one place to look. A well-kept monolith is a better home for them than forty services nobody fully understands.
Why I still bet on the monolithWhen you don't have twenty engineers, agents turn one person into three or four. That matters most in places like Lahore, and the window for being early won't stay open.
AI tools vs. AI agents07 / More receipts
The book →
"Takes full ownership of his work."
"Working with Sajjad is a blast!"
08 / Next
Hard backends, agents in production, whole products built in plain English, and systems that touch money or the real world. I like talking about all of them.
GET / HTTP/2 Host: sajjadumar.dev Accept: application/json HTTP/2 200 content-type: application/json vary: Accept, User-Agent
More and more, software reads a portfolio before a person does, so I gave it a proper front door. Nothing here is a mock-up: these are live endpoints.
curl sajjadumar.dev
curl -H 'Accept: application/json' sajjadumar.dev
{ "mcpServers": { "sajjad-umar": {
"type": "http",
"url": "https://sajjadumar.dev/mcp"
} } }
Tools: get_profile, get_experience, list_projects, search, get_contact. Read-only, no auth.
curl -X POST sajjadumar.dev/ledger \
-H 'Idempotency-Key: pick-any-key'
Run it twice. The first call returns 201, every repeat returns the same entry with 200. Read the ledger and check the hashes yourself.
These buttons send real JSON-RPC requests to /mcp, the same ones an agent would send.
→ POST /mcp
Pick a call above.
← response
Loading /me.json…