One VM to a GKE platform
Moved a live building-operations platform off a single Docker Compose VM and onto Kubernetes.
One VM, Docker Compose, one in-memory queue
One failure domain, deployed by hand, and a queue that could not be shared.
Open to 2027 roles in SRE, cloud and AI infra
I run cloud platforms in production and benchmark AI infrastructure. DevOps intern at Primustech, Computer Science at NTU.
169 merged PRs on a production IoT platform · 7 case studies with working models · 320 LLM agent runs benchmarked
~15%
cloud spend cut across monitoring, database and compute
169
pull requests merged into a production IoT platform
320
long-horizon LLM agent runs benchmarked for my final-year project
3.02x
throughput from running four isolated agent tasks at once
Where these numbers come from, and which ones you can check yourself
Things I shipped at Primustech, each a small working model of the real system. Press the buttons.
What I work on, and the colour each one wears across this site:
Primustech · Kubernetes on GKE
Moved a live building-operations platform off a single Docker Compose VM and onto Kubernetes.
One VM, Docker Compose, one in-memory queue
One failure domain, deployed by hand, and a queue that could not be shared.
I own the Cloud Build delivery pipeline: build once, promote by digest, approve before release.
A simulation of the real release gates.
Measured first, then cut monitoring, database and compute, with every trade-off written down.
Dashboards and alerts built around how this system actually fails.
leader
follower
follower
Quorum held, 3 of 3 up
All quiet.
The platform could watch a building's air-conditioning. Letting it switch units on and off took a different kind of care.
control bridge
dry run
commands this hour 0/6
air-conditioning unit
26 °C from the plant's readback
selector auto
Security and reliability changes to a running platform, each split so that no single step can take it down, and rehearsed first.
Cache
open
No password anywhere
The cache accepts any client inside the cluster. Flip a switch to start the change.
The building IoT platform I run on GKE: how traffic moves through it, what I alert on and why, and where the money went.
How internet traffic reaches the cluster: load balancer, WAF, ingress, Services, pods and the database.
BrowserHTTPS 443
One public hostname. Any other host, or the raw IP, gets a 404 by design.
Global HTTPS load balanceranycast IP
TLS ends here on a reserved global IP with a Google-managed certificate.
Cloud ArmorWAF
OWASP CRS rules plus a login throttle, tuned per route so legitimate traffic passes, with auth and rate limits behind them.
GKE IngressL7 paths
Path routing sends the device API, the REST and WebSocket API, and the web UI to separate Services.
Service to podsClusterIP
Core API pods are spread across three zones and across nodes, so losing a zone costs a third of capacity, not all of it.
Core API to Cloud SQLprivate IP
A Cloud SQL Auth Proxy sidecar connects over private service access using Workload Identity: no key files, no password on the wire.
Primustech's AI agent platform gives facility teams two agents: an operations agent that answers from the IoT platform's live readings, and a document assistant that answers from company documents. I deploy and run it on Google Cloud. Follow a request through it, see the AI infrastructure layer by layer, and switch on the lens to see which parts are mine.
Answers facility managers from live building readings. A manager agent plans; a data-engineer agent queries the IoT platform and crunches the numbers.
Agno team on Cloud Run, Gemini on Vertex AI
Answers from a company's own documents, with citations: multi-stage RAG over Milvus, with a reranker on a GPU.
Cloud Run API and job, Milvus, Gemini via OpenRouter
Building data comes from Building IoT platform, the platform I run on GKE; it has a chapter of its own.
Infrastructure for the company's two AI products: an operations agent that answers from live building data, and a document assistant.
Question
from a facility manager
Agent team
Agno on Cloud Run
Data
live readings, documents
Gemini
Vertex AI, OpenRouter
Answer
traced with tokens and cost
The operations agent: a small team of AI agents that answers facility managers from live building data.
Step 1 of 8
A facility manager asks something like "which floors ran warm this afternoon?"
My final-year project at NTU's HyScale Lab. I got ARIES, the lab's open-source framework for agent-serving experiments, running long tasks against live apps (mail, a shop, an LMS), then measured 320 runs on a hosted API and self-hosted SGLang on an A100. Since then: what MCP tool servers cost, and the whole stack running on a supercomputer without root.
Runs per hour on one 8-vCPU VM
Mean of three blocks, bars show the range
| At once | Attempts / h (range) | Passed / h | CPU | Memory |
|---|---|---|---|---|
| 1 | 13.7 (13.5-14.1) | 10.7 | 15% | 2.6 GiB |
| 2 | 23.8 (22.4-25.1) | 17.3 | 26% | 3.9 GiB |
| 4 | 41.5 (36.3-45.7) | 29 | 48% | 6.4 GiB |
Where a run's wall clock goes
Inside the agent phase, MCP tool calls are only 2.7% of the time
Where an agent's time goes
48 runs with the agent's own spans switched on. The model's turns are most of it; MCP tool servers are 8.6% here.
What one call costs, by server
Each bar runs from the median call to the 95th percentile, on a log scale. Nine of the thirteen servers, 800 of 874 calls.
Servers that reach the internet are slow with long tails: a browser call takes 1.4 s at the median, and an arXiv search 11 s at the 95th percentile. Two ideas would save memory, not time: starting a server only at its first call adds about 1.2 s per server, roughly as much as all the MCP waiting in a run, and restoring an idle application from a snapshot takes about 1.5 s.
Why a long agent run doesn't recompute everything
Every turn re-sends the whole conversation. A prefix cache keeps what the server has already seen, so only the new tokens are computed.
Measured, not illustrated: across 320 runs, 96% of input tokens came from the prefix cache, on a hosted API and on self-hosted SGLang. This illustration reaches 94% at 24 turns.
A GPU in one place, the agents in another
Qwen3-4B served with SGLang on an A100 at NSCC, Singapore's national supercomputer, for agents running on Google Cloud.
NSCC A100
SGLang server
Qwen3-4B
Google Cloud VM
ARIES runner
task sandboxes, live apps
GPU time the serving jobs held
GPU time the agent runs used
The serving jobs held the A100 for about 7× as long as the agent runs used it. A reserved accelerator that sits idle is the AI version of an oversized pod.
The same stack on a supercomputer, without root
I added an Apptainer backend to ARIES so a whole run fits in one batch job on NSCC's ASPIRE 2A: the agent, its sandbox, and Qwen3-4B served by SGLang on the same A100 node. Merged 10 Nov 2026: 6,678 lines across 46 files.
what broke
ARIES started every part of a run as a Docker container, and an HPC cluster gives users neither Docker nor root.
what it does instead
The harness and the sandbox run as Apptainer instances, each with a fake root and its own overlay; the bridge runs as a process in the same namespace. Images are unpacked once into plain directories owned by the user, because with a packed image underneath, installing a package as "root" fails on files owned by other IDs.
ICCV 2025, co-author
The first video LLM that learns a person from a single reference video, so it can answer identity-aware questions about them.
Code and paperFrom PLCs in a building's control room to Kubernetes in the cloud.
Singapore
Also
Jul 2023 - Jun 2027
Nanyang Technological University
Bachelor of Computer Science
Exchange semesters at Tsinghua University and Luleå University of Technology.
A small retrieval service over everything on this site, with an optional LLM on top. It answers only from these facts, shows its sources, and shows its own OpenTelemetry trace.
Try one of these
Prefer your own assistant? This site is also an MCP server: point Claude, Cursor or any agent at it.
The Go server that sent you this page also reports on itself. These numbers are live and refresh every five seconds. Below them: the site's own SLO as Google's uptime checks see it, how it ships (DORA metrics), and the trace of your own visit.
Latency of the last requests
OfflineThis site's own SLO, measured from outside real data
Objective: 99.9% over 30 days
SLI: the share of Google Cloud uptime checks that get a 2xx from /api/health within 10 s. They run every minute from Singapore, Belgium and Oregon.
How this site ships, measured
DORA metrics, last 30 days, as of 12 Nov, 10:04 UTC
Before a release reaches you: 0 releases stopped before taking traffic, 0 releases held by the error-budget gate, 0 automatic rollbacks. Last rollback drill, 19 Oct, 12:05 UTC: traffic back on the old revision 17 s after the switch.
30 days agodeploys per day, Singapore timetoday
Computed by the pipeline from this repository's commits and deploy runs as of the time above, before it built the image you are looking at. Each release starts with no traffic and is smoke-tested at its own URL first; a deploy counts as failed only if its revision took traffic and then failed the live checks, and a failure there rolls back on its own. Problems that did not come from a deploy are in the postmortems.
Your visit, traced
Measured by your own browser. Nothing is sent anywhere.
Blameless postmortems from building and running this site: timeline, root cause, how it was caught, and what changed. The times and numbers come from the commits, the CI history and Cloud Run's request logs.
Want to be on the other side of one? Go on call for a simulated incident, and get a postmortem of your own response.
Near miss1 Oct 2026
For the site's first 3 h 32 min, the contact form said a message was sent while keeping it on a disk that Cloud Run throws away.
3 h 32 minthe form could lose a message
6 of 6 actions doneRead it
Near miss1 Oct 2026
Cloud Run's front end answers some paths ending in “z” itself, so /healthz returned 404 to every outside check while the app was healthy.
0visitors affected: caught before launch
3 of 3 actions doneRead it
False alarm1 Oct 2026
The smoke test reported /metrics as broken while Cloud Run's logs showed every /metrics request returning 200.
43 / 43requests to /metrics answered 200 during the replay
3 of 3 actions doneRead it
Longer notes on what the measurements showed. The numbers are the same ones the rest of this site uses.
ARIES agent benchmarks11 Nov 2026 · 4 min read
ARIES started every part of a run with Docker. A supercomputer gives users neither Docker nor root, so I added an Apptainer backend: 6,678 lines, a way to measure containers that have no cgroup, and one hang that looked like the agent's fault.
Read itARIES agent benchmarks19 Oct 2026 · 2 min read
MCP tool calls were 2.7% of an agent's time, 96% of its input tokens came from the prefix cache, and the GPU sat idle most of the time it was held.
Read itBuilding IoT platform19 Oct 2026 · 2 min read
Managed Prometheus was the third-largest line item and nobody had measured why. Attribution first, then a reaper, then dropping what nobody read.
Read itI graduate in June 2027 and I'm looking for SRE, cloud, DevOps and AI infrastructure roles.