I build AI systems that run on their own and still prove what they did.
Behind them are 18 years of running a technical business: an agency, live servers, and a
P&L. I replace fragile prompts with real engineering, a human approval step before
anything goes out, and interfaces people can actually use. Currently looking for a
senior Applied AI Engineer role in Singapore.
I do not just use AI. I build pipelines that run, measure their own results, and
change the next run themselves, with nobody editing a prompt.
⚑
The Human Gate
Running on its own does not mean nobody is watching. Drafting and review are
separate agents, and every pipeline stops for a person to approve before anything
goes out.
▣
UI/UX & Usability
A decade of agency design behind it. Every AI tool I build has to be usable by the
person who actually does the job, not just correct.
⚿
Hardened Security
Years of running live servers and real databases. My AI runs locked down: it can only
reach the few domains it needs, and it cannot touch data it has no business touching.
▲
Commercial Pragmatism
I have run a P&L and a number one selling product. I only build AI that solves a
real operating problem, and protects the brand while it does it.
▤
Full Stack Execution
I do not just write prompts; I build the entire housing. From spinning up the Linux
VPS and configuring the egress firewalls, to wiring the API and MCP integrations and structuring
the databases, I execute the complete pipeline.
The Systems
Production-grade architectures
Six systems I led from architecture to release, now running in production, from live web
apps to a printed book. The hard part was never the prompts. It was securing the machines
they run on, fitting them to how the business already works, and making sure the numbers
they produce are right.
How each system was built, what broke in production, and what I changed to make it
reliable. Every one includes the mistake I made first, and what it saves now that it works.
01
AI Speaking Examiner
A public web app. A student scans a QR code printed in the
book, records an answer in the browser, and gets a Cambridge-aligned score straight
away.
Live · aeis.learnintt.com
What it savesabout 20 hoursOf marking returned, per monthScoring one recording against four rubrics takes a teacher about
ten minutes, so a class of 30 is five hours. At one class a week that is twenty hours a
month. The app returns each score in about seven seconds, at any hour.
How it was built90%Built with applied AICode, copy and interface drafted by agents I directed. The rubric
rules, and the decision to take scoring off the model, are mine.
Read the buildHide the build
The hard part was being fast and consistent at the same time. The app takes a
recording, transcribes it, and returns a score against four Cambridge rubrics in about
seven seconds. A parent will not wait much longer than that. A score that changes when
you submit the same clip twice is worse than no score at all.
So the model no longer returns a score. It returns a transcript and four true or false
answers: did the student cover each required point. Code turns those into the score, and
caps it by length. Grammar and pronunciation stay with the model, because those are real
language judgements. Same recording, same score tomorrow.
27 topics, and the screen a parent reaches by scanning a QR code printed in the book.
What I got wrong first
I asked the model for a 0 to 5 score and trusted it. Weak test clips came back at
4 out of 5, because the model was generous every time. A generous score is worse than a
wrong one when a parent acts on it. So I took the decision away from the model. It now
returns a transcript and four true or false answers, and ordinary code works out the
score.
Scope
27 topics · 4 rubrics
Model
Gemini, audio-native
Runs on
n8n · Caddy · Hetzner
Reached via
17 printed QR codes
My role
Lead: architecture, build, release
02
Autonomous Content Pipeline
A Claude Code agent that drafts and checks the daily social
posts on its own, on a server with nobody watching, then stops until a person taps
approve on their phone.
Private · Walkthrough On Request
What it savesabout 90 hoursOf my time, per monthOne finished post used to take me three to four hours. The pipeline
produces about one a day, and my part is a two minute approval on my phone. 45 posts
approved so far: 19 published, 26 queued.
How it was built95%Built with applied AIThe agent researches, writes, designs and checks its own drafts. I
set the gates, the container rules and the brand limits it works inside.
Read the buildHide the build
The hard part was running unattended code safely. A system that publishes to a
real brand with nobody watching is a risk to that brand. So nothing reaches an audience
until a person taps approve. The writer is fully autonomous. The publisher is not. That
line is the whole design.
n8n workflow
The draft moves on its own until the gate, then stops until a
person approves. Nothing has ever published without one. Every arrow in this picture
is an n8n step, not a decision the model makes.
Why n8n runs the steps, and not the AI. The AI is not consistent about
how it does a job. Ask it the same thing twice and it may take a slightly
different route, and a slightly different route gives you a slightly different result.
For writing a post, that variety is the point. For uploading an image, writing the row,
waiting for the slot and calling the publish endpoint, it is a defect. n8n does those
steps the same way every single time, and when one fails it fails in a named node I can
open and read. So the model does the language, and n8n does the plumbing.
n8n does the steps
10 runs of the same jobSame path, every run. Upload, write the row, wait for the
slot, publish, verify. A failure stops at a named node.
The model does the steps
10 runs of the same jobSame brief, different route. It may skip the verify, retry
in the wrong order, or invent a step. Nothing to open and read afterwards.
I built this inside a hardened container: a non-root user, no host folders mounted, no
access to Docker itself, and a firewall that lets traffic out to about twenty domains it
needs and blocks everything else.
# container egress: allowlist, then reject everything else
iptables -A OUTPUT -m set --match-set allowed-domains dst -j ACCEPT
iptables -A OUTPUT -j REJECT# verified after every build:# example.com -> blocked github.com -> 200 whoami -> claude
9:41
‹CPContent Pipeline bot
CAROUSEL 1080 x 1080Draft ready for Thursday.
3 comprehension traps that cost easy marks. Swipe for the fix.
09:41ApproveReject
What I got wrong first
The writing agent made up teaching methods that sound exactly like ours, complete
with an acronym, and none of them are in our books. You would only catch it if you knew
the source material well. Telling it not to do that in the prompt was not enough, so I
added three separate checks that run before the post ever reaches the human gate.
It also checks its own results. Twice a month the pipeline pulls the real
engagement figures for the posts it published, compares each one against what it
expected, and writes the answer back into the brief the writer reads next time. That is
how it worked out that reels reach about four times as many people as carousels, and how
it stopped chasing a Facebook reach figure that Meta had quietly retired. Nobody edited a
prompt to teach it either. It measured, and the next brief changed.
Status
Unattended since Jul 2026
Isolation
Non-root · no docker socket · 20-domain allowlist
Auth
Service accounts, no OAuth expiry
Self-review
Bi-monthly, from live post data
Published unapproved
Never
03
The Calendar You Can Text
An internal tool that reads a sentence like “open
Wednesdays 8pm through November” and updates the live booking calendar. One command
undoes it.
Private · Walkthrough On Request
What it savesabout 5 hoursOf admin time, per monthOpening a month of Wednesday evenings used to mean editing every
matching row in the booking sheet by hand, and checking each one against live bookings.
It is now one sentence.
How it was built95%Built with applied AIThe parser, the date expansion and the tests were AI-written. The
refusal rule and the 200 row cap are mine, and they are what the tests protect.
Read the buildHide the build
The thing that mattered was never overwriting real data. The bot has to follow
a conversation, work out what a repeating date rule means, and refuse to touch any slot
that already has a booking in it. So the model never sees the calendar. It only turns a
sentence into a rule. Turning that rule into real dates happens in ordinary code.
// "open Wednesdays 8pm through November"
{
"action": "open",
"weekdays": ["WED"],
"from": "2026-11-01",
"to": "2026-11-30",
"times": ["20:00"]
}
// dates expand in JS, where a calendar bug is a failing test// and not a parent booking the wrong evening.
The model does language. The code does calendars.
9:41
‹CBCalendar bot
open Wednesdays 8pm through November20:04
Confirmed. Unlocked 4 slots for Wednesdays at 20:00.
1 conflict found and skipped.20:04
What I got wrong first
I matched calendar rows on date and time. The tool I was using only ever
matched on the first column, and said nothing about it, so my matching had quietly
dropped to date only. The first time a date held two different sessions, it would have
written over a real booking. I found it in testing before launch. The lesson is that a
tool you did not write can change what your code means without failing.
Safety
Never touches a booked slot · 200-row cap
Undo
One command
Tested
27 unit tests, live E2E
Unauthorised chats
Ignored in silence
04
A Workforce Of 28 Specialist Agents
The team the other systems are built from. Twenty-eight
specialists, each allowed to do a deliberately different amount, and a public field
guide generated from the files actually in use.
Live · social.learnintt.com/agents
What it savesabout 8 hoursOf upkeep, per monthThe field guide is generated from the real agent files, so one page
shows every agent I have and is right the moment one changes. Keeping a written guide to
28 agents current by hand costs about a day a
month, and it is stale in between.
How it was built85%Built with applied AIThe agent files and the office illustration were AI-written. Who
is allowed to touch what, and which agent exists at all, is mine.
Read the buildHide the build
The rule was that a reviewer must not be able to hide a problem. Every
quality-control agent is defined without the tools to write files. It cannot fix what it
finds, so it has to report it. Give a reviewer the ability to edit and it quietly patches
the symptom instead. The report comes back clean, and the pattern never reaches the
person who could change the process.
The field guide is generated from the real agent files, not written next to them, so
it cannot end up describing a workforce that no longer exists. The illustration below is
drawn from the same roster.
Not a live feed. The roster is real; the working day is
a timer running in this browser. Scroll it sideways to see the whole floor.
Each desk is one agent that exists as a definition file. Reviewers are
drawn at work like everyone else. What separates them is what they are allowed to
touch.
What I got wrong first
I wrote a test to prove no agent could walk through furniture. It reported six
problems, which reads like a near pass, while the office on screen was still visibly
walking people through their own desks. The test was skipping the desk each agent was
heading for, because a chair does sit inside its own desk. That one exemption covered
the exact failure I was looking for. Narrowed to the small legal gap between a seat and
its approach point, the same code reported 146. A test that excuses the thing it is
testing will report clean forever.
Roster
28 agents · 4 teams
Reviewers
No write tools, by definition
Field guide
Generated from the definitions
Scene
Illustration, never presented as live
05
Hybrid RAG Knowledge Base
A search layer over my Obsidian notes. They are indexed two
ways at once, so an agent can find the two notes it needs instead of loading whole
folders.
Private · Runs On My Own Machine
What it savesabout 100,000Tokens not read, per sessionThe vault is about 75,000 words. Loading all of it to use one
paragraph costs that on every session, and it grows every week. Retrieval returns about
400 words instead.
How it was built90%Built with applied AIThe indexer, the session hooks and the graph extraction were
AI-written. The duplicate gate was set on real duplicates, by me, not on taste.
Read the buildHide the build
The problem is that a model starts every session knowing nothing. It works
out again today what it already worked out yesterday. The obvious fix is to load the
whole project at the start, and it is the wrong one. The vault is about 75,000 words.
Loading it means paying to read all of it in order to use a paragraph of it, and that
bill grows every week the vault does.
So there are two indexes, because two different kinds of question get asked. A
knowledge graph answers questions about structure: what connects to what, which
notes belong together, which few notes everything else hangs off. A vector
database answers questions about content: what does the note on this subject
actually say. Ask the graph which note. Ask the vectors what is in it. Think of the
notes as the books and this as the index at the back that tells you which book to open.
Retrieval gets more accurate as the vault grows, not less, because more notes give both
layers more to sort on.
Two hooks make it automatic. One runs when a session opens and hands over the map and
the open task list, so work starts already knowing the shape of the project. One runs
when it closes and writes the session back out, so what was learned is still there
tomorrow.
The store only rebuilds a note that is genuinely newer than the last build. The graph
report opens by saying whether the vault is still small enough that I do not need a graph
at all, which is the sort of thing a tool should be willing to say about itself.
Not the real graph. An illustration of the idea: notes
as nodes, the few hubs larger, retrieval travelling the links between them.
The vault holds notes. The graph holds how they relate. A question that
names a subject goes to the vectors; a question about how two things connect goes
here.
$ python rag_query.py "how do we handle the human approval gate" --n 2
Top 2 results for: "how do we handle the human approval gate"
#1 [0.3927] 03-Claude-Brain/Social-Auto-Pipeline.md (chunk 0)
Goal: automate the work around a post, but never the
decision to post. Every day n8n starts a run, a
containerised Claude Code generates and self-QCs two
posts, they land in the sheet as Pending approval, a
human approves each from a phone, and n8n publishes
only the approved ones.
#2 [0.3434] 2026-08-12b_hook-score-telegram-analyst....md (chunk 2)
One question, two passages, about four hundred words returned instead of
two whole files. The scores are how close each passage is to the question. They are
shown on purpose: a weak top score is the signal that the vault has nothing on the
subject, and that is worth seeing.
What I got wrong first
I assumed writing something down was the same as remembering it. A job that starts
the model fresh every morning has no memory of yesterday, and mine happily produced
nine posts covering three ideas, each one three times. My first instinct was a firmer
instruction telling it not to repeat itself. That cannot work. The instruction and the
input were the same every morning, so the output was too. The fix was a list of what
had already shipped, kept outside the repository so a reset cannot wipe it, and a
similarity check that stops the run rather than asking politely. I set the cut-off on
the real duplicates, which scored 0.50 and above, not on what felt right. Genuinely
different topics scored 0.13 and below.
Vault
86 notes · about 75,000 words
Stored facts
225 separate memories
Retrieval
Knowledge graph, plus vectors
Index
ChromaDB · 400-word chunks
Embeddings
On this machine, nothing uploaded
Loaded per session
A map, never the vault
06
A Printed Book, Built Like Software
A 122-page bilingual speaking guide for Singapore’s
AEIS entrance exam, typeset from source files, printed in the thousands, and on sale
now.
In Print · On Sale
What it savesabout 120 hoursOf layout and checking, savedThirty-eight numbered builds before v38 went to the printer.
Re-flowing 122 bilingual pages by hand for each editor batch is about three hours a
round. Here every batch is an edit and a recompile.
How it was built75%Built with applied AIA former MOE teacher provides the content. AI rewrites and tightens
it, then does the layout and the checks. The cover is about half generated and half
Photoshop by hand.
Read the buildHide the build
The hard part is that print has no patches. A web page can be fixed an hour
after someone notices. A print run cannot. Every claim in the book had to be true before
the file left for the printer, and the layout had to survive being rebuilt from scratch
late in the schedule.
The inside of the book is a text file. Typst turns it into a print-ready PDF, so a
change from the editor is a small edit and a rebuild, not a person re-flowing 122 pages
by hand. Four agents do the chapter work: one writes to the required Cambridge level,
one reviews the writing, one places it into the layout, one checks the finished PDF. As
everywhere else here, the reviewers cannot edit.
I did not write this book. The author is a former MOE teacher who runs the centre it
came from, and the editor works with us. Their changes arrived as dated batches of
marked-up screenshots, which I applied to the source. My side was production. The cover
art was generated as two separate layers, the children and a faint Singapore skyline
behind them, then put together in Photoshop, because the title area needed a person’s
eye rather than another prompt. The back cover is built by the same pipeline as the rest
of the book, barcode included.
Accuracy is where I was most suspicious. The pronunciation spellings for 158 words
came out of a model, and eleven of them were wrong. A line claiming the book had QR
linked audio was also invented, and cut, because the author’s material never
mentioned audio. A “100 per cent placement” headline came down to the 97 per
cent the records actually support.
Front and back of the printed edition. The barcode is drawn from the
issued ISBN at build time, so the number under it and the artwork around it cannot
drift apart.
What I got wrong first
The source file was not in version control. A tool error wrote over it, there was
no history to restore from, and the only complete copy of the book left was a PDF. I
rebuilt the source from that PDF and the text came back complete, which is exactly
what made it dangerous. Every page with a custom layout had quietly gone back to a
default, and the back cover had lost the publisher logo and the ISBN barcode
completely. Comparing the text showed none of it. That version was days from a print
run of thousands, and the first person to notice a missing barcode would have been the
printer. It is tracked now, and after any rebuild every designed page is compared
against the last known good PDF as a picture, not as text.
Format
122 pages · English and Chinese
Source
Typst, compiled to print-ready PDF
Cover
Generated layers, composited by hand
ISBN
978-981-94-6269-8
Print run
Thousands of copies, offset
My role
Production, not authorship
How I Work
Engineering philosophy
18 years in technology has taught me that AI is the unpredictable part of any system. I
treat a model as an input I do not trust, and put ordinary engineering safeguards
around it.
✓
Do not let the model decide
When a wrong answer costs something real, the model should not be
the one doing the maths. Let it read and understand: transcripts, yes or no answers, what
a sentence means. Then let ordinary code work out the result.
⚑
Enforce a mandatory human gate
Letting AI draft on its own saves a lot of time. Letting it
publish on its own is a risk to the brand. Drafting and review are separate agents, and the
work always stops for a person to approve before anything goes out.
⚠
Design for silent failure
AI does not crash when it is wrong. It returns something that
looks right, or a tool quietly stops matching what you think it matches. Never rely on one
instruction in a prompt for safety. Build separate checks that can each catch it.
Background
Technical & commercial foundation
18 years across code, design and the P&L. That is why these pipelines are secure,
usable, and worth what they cost to run.
Building with today: JavaScript & Node · Python ·
HTML/CSS · n8n · Make.com · Claude Code · agentic workflows ·
Gemini API · Docker with hardened containers · REST API integrations ·
Linux & Caddy Earlier foundation: PHP · MySQL · live database management ·
WordPress · Magento · UI/UX design
2025 →Applied AI Systems Builder. Leading production AI systems from architecture through to release. I build multi-agent pipelines by directing agents rather than writing every line by hand. The aim is always the same: systems that run without me, and still stop for a person before anything leaves the building.
2021 →Corporate Services Manager. At a Singapore marine and industrial engineering firm, alongside the work above. I report to the Managing Director and Chairman and turn their strategy into how the operation actually runs: administrative workflows, staff scheduling, HR compliance and financial administration. The remit is deliberately mixed. The same week can involve the company servers and web infrastructure, a payroll filing, and a fire safety inspection.
2020 →Head of Product & Technology (Co-Owner). Directing technology, design, marketing, book production, and overall P&L. Scaled a flagship PSLE Oral title to the #1 best-selling spot on Shopee and secured physical distribution across Popular bookstores, managing demand forecasting and print runs of thousands of copies.
2008–20Lead Developer & UI/UX Strategist (Co-Founder). A decade of building for clients and running an agency. Hands on with UI and UX design, HTML/CSS, PHP, live databases, WordPress and Magento. I ran the projects, led the developers, and trained the clients to use what we had built for them. The security habits and usability standards I apply to AI infrastructure today come from here.
Why look for a full-time role when I already co-own a business?
Because the business now runs on the systems above. That was the point of building
them. What it cannot give me is harder problems. One small publisher produces a limited
supply of them, and building alone means nobody reviews my thinking or pushes it further.
I want to do this full-time, on systems bigger than a company of my own will ever justify,
with a team to argue with. I have spent 18 years being the person who owns the outcome, and
that does not switch off when the job title changes.
Want systems like these on your team?
I am looking for a full-time role in Singapore, building and running AI systems that hold
up in the real world. If you are hiring an Applied AI Engineer, and you want
someone with 18 years of commercial judgement who treats a model as something to be checked
rather than trusted, I would like to hear from you.