Latest
IceBase: Firebase's API, a declared schema and a way out
12 Nov 2026 / 5 min read / firebase, typescript, postgres, open-source
Firebase is my go-to for side projects and there is no overnight way off it. IceBase keeps Firebase's API, requires a declared schema and indexes, and runs on firebase, SQLite or Postgres per service.
Earlier
10 Nov 2026 / 5 min I built an open-source Canva alternative with 42 MCP tools Digital Canvas is an Apache-2.0 design editor on Skia WASM. Designs are .dcanvas files you own, it opens without a login, and agents can drive it through 42 MCP tools.
5 Nov 2026 / 4 min Three ways into a client's on-prem server, and where the client's switch sits On-Prem Manager can now reach a client's server through an encrypted browser tunnel, the agent GUI on the cloud's own domain, and port tunnels. What each one does, what it doesn't hide, and how the client turns it off.
3 Nov 2026 / 6 min A kanban board for AI coding agents: 12 stages, 6 repos Orch2 turns a ticket board into the control panel for coding agents: a plain script runs 12 stages, agents only write code, and every ticket gets a sandboxed copy of the product.
2 Nov 2026 / 4 min Release-based planning: only the release gets a deadline For 6 months as a Tech Lead I couldn't say no, and every deadline slipped. My answer was two shifts: plan releases, not features, and make the product document the source of truth.
26 Oct 2026 / 5 min 944 lines that turn a ticket into a headless Claude Code session I hand work to Claude Code through tickets, not a terminal. A 944-line orchestrator with zero dependencies pulls each ticket, runs one headless session per ticket, ends the turn on a question and resumes it on the answer. It is open source (MIT), together with the tracker.
25 Oct 2026 / 5 min Replacing Node-RED with a 10 MB browser editor and a start.sh Every on-premise Envizom deployment needs a few client-specific API integrations. Node-RED made a five-call Promise.all a research project, and a per-client repo broke the day a client cut the server off the internet. codeshell is the replacement: one Go binary in a container, an editor and terminals in the browser, and a start.sh that brings the integration back on every restart.
24 Oct 2026 / 12 min 90/10: what we took away from our AI coding agent, and why Our first agent pipeline at Oizom let the coding agent run git and deploy steps too. It was slower, cost more, and when it failed it failed differently each time. This is the full pipeline as it runs now, column by column: the ten jobs scripts own, what the agent still does, what stays with people, what it costs, and what broke on the scripted side.
23 Oct 2026 / 7 min On-Prem Manager: one engineer per two on-prem Docker sites didn't scale Governments want their air quality data on their own servers, so on-premise is how Envizom sells. Docker Compose and Portainer got us to about five deployments a year with one engineer per two of them. On-Prem Manager is what I built to go past that: a cloud console with git-style commits per site, and one Go agent per server that snapshots, applies, verifies and rolls back, even with no internet.
22 Oct 2026 / 5 min 90% of our AI coding agent pipeline is plain scripted code In our dev pipeline at Oizom, an AI coding agent does the engineering work inside one ticket's isolated stack. Everything around it, from provisioning to merge, deploy, health checks and rollback, is scripted. We tried giving the agent more first. It was slower, cost more, and was worse at the boring parts.
21 Oct 2026 / 5 min 0 reads to switch views: Firestore board filters in the browser Firestore can't OR across fields and wants a composite index per filter combination, so my tracker loads a board's active tickets once and runs filter, sort, group-by and swimlanes as one pure function in the browser. Switching views costs no reads. The ceiling is about 5,000 active tickets per board.
20 Oct 2026 / 5 min Ticket keys in Firestore: issued once, never reused after delete In my tracker, ENG-42 is a name, not an identity. Tickets get a generated id, keys live in their own index, a key is issued once by a counter and never again, and a deleted ticket leaves a tombstone so old links say 'deleted' instead of opening someone else's work.
19 Oct 2026 / 5 min 10 TypeScript files, 5 SDK artefacts: typed in Node and Deno My tracker's TypeScript SDK is 10 source files and one build script. The script concatenates them into a single file and derives five artefacts from it: sdk.ts for Deno and Bun, a flat sdk.d.ts, sdk.js and sdk.min.js, and an npm tarball. Then fixtures prove the types arrive in every runtime, and the deploy refuses a stale build.
18 Oct 2026 / 5 min llms-full.txt for agents: 6,245 lines, 1,800 written by hand My tracker publishes one 6,245-line Markdown file, /llms-full.txt, that tells an agent everything it needs to work there. About 1,800 lines are prose I write. The rest is generated from the OpenAPI document, the MCP registry, the shared contracts and the SDK's declaration file, and the deploy fails if the committed copy is out of date.
16 Oct 2026 / 6 min Polling was 88% of my API calls: agents now wake on Firebase SSE Two orchestrator loops polling every 30 seconds were 88% of every request my tracker's API served. Now an agent holds one Realtime Database stream on a tiny revision node, and calls the API only when that node moves, asking for the delta. Here is the node, the credential, and the two details that keep a flapping stream from turning back into a poll.
14 Oct 2026 / 5 min MCP on OAuth 2.1: one URL and a consent click, no API key My tracker's MCP server takes OAuth 2.1 with PKCE and dynamic client registration instead of a pasted API key. A person adds it in Claude with one URL and a consent click, picks the boards it may touch, and can revoke it in one place. Here is the flow, the token lifetimes, and the one rule that catches a stolen refresh token.
13 Oct 2026 / 4 min Our coding agent prompts live in the ticket, reviewed like PRs On my team at Oizom the only way to talk to the coding agent is the ticket thread, so every prompt is stored with the work it produced, next to the preview, the feedback and the cost of each turn. That makes a prompt something you can read back and review like a pull request.
11 Oct 2026 / 5 min 1 human check, 8 scripted steps: QA in our coding agent pipeline Our coding agent never marks its own work as done. It posts a preview link and moves the ticket to QAQC, a person tests it, and only after that do eight scripted steps take the change to the dev environment. Why we kept that one step human at Oizom.
10 Oct 2026 / 8 min 849 KB of spec before any code: building Octupuz, a puzzle feed Octupuz is a feed where every post is a puzzle. The backend knows nothing about puzzles: a post is a seed, the phone draws the board, and a finish only counts after the server replays the move log through the same rules code.
5 Oct 2026 / 5 min Headless Claude Code asks, exits, then resumes on the answer When my coding agent needs a decision, it asks in the ticket and ends its turn. No polling, no process left waiting. The answer starts claude -p --resume on the same session, with the values in the prompt.
3 Oct 2026 / 5 min 52 commands, 3 doors: the app, REST and MCP share one write path My ticket tracker has three ways in: the app, a REST API and an MCP server. All three call the same 52 commands, and Firestore rules deny every other write. An agent with a token can do nothing a person couldn't, and the price is 150 to 400 ms a write.
2 Oct 2026 / 5 min Agent health from a 60-second heartbeat: derived, never stored In my ticket tracker an agent's status is never stored as alive or dead. The orchestrator beats once a minute, and every screen works out the dot from the age of the last beat, so a crashed agent turns red with no write from anyone.
30 Sept 2026 / 4 min One stack per ticket: why our coding agent works on a DB copy Every ticket on our board gets a branch in every repo, its own services, a copy of the dev database and a preview URL. It started as a fix for branch mistakes. It is also what keeps a coding agent's worst case small.
28 Sept 2026 / 5 min $402 on one ticket: cost per turn in headless Claude Code One ticket reached $402 over nine headless Claude Code runs and nothing in the app said so. The catch when you fix that: total_cost_usd is cumulative across --resume, so run 8 made one API call with zero output tokens and reported the same $392.83 as run 7.
26 Sept 2026 / 7 min The ticket is the interface: how our developers ship without a laptop How a small team turned its ticket tracker into the only developer interface: per-ticket stacks with their own DB copy and preview URL, an AI agent driven from the ticket thread, and a scripted orchestrator that merges, deploys and rolls back.
22 Jul 2025 / 7 min 1 million readings, 2 GB of RAM: Node.js typed arrays over JSON Our Oizom backend ran out of memory on a 2 GB droplet whenever a report touched a million sensor readings held as JSON objects. Two typed arrays and one class fixed it. The first version was 8x slower than JSON.parse; dropping sorted rows made the second one faster.
13 May 2025 / 4 min await on a sync function: 2 ms to 51 ms for 1M calls in Node.js A million calls to an empty sync function take 2 ms in Node.js. Put await in front of it and the same loop takes 51 ms; in Chrome, 3 ms becomes 1,500 ms. The benchmark, the numbers for Node, Deno, Bun and Chrome, and why.
25 Jan 2025 / 13 min Postgres triggers invalidate our Redis cache at Oizom Cache-aside in Redis served stale reads whenever a write came from outside the app. How we moved cache invalidation into Postgres triggers at Oizom, and the listener that made it safe across instances.
15 Jan 2025 / 6 min 5 seconds to 30 ms: rebuilding IDW heatmaps in Go Our air-quality heatmaps took about 5 seconds per image on an hourly Python cron. An on-request Go service with precomputed weights and JPEG instead of Base64 PNG does 20 images in 30 ms, for any past time range.
4 Jan 2025 / 9 min Request-scoped logging in Node.js and Express at Oizom Every request in our Express APIs at Oizom gets a context id, every function logs through context.log, and the logs of a request are kept only when it fails or the frontend asks. One id then gives you every API call by a user, and from there the full log of the request that broke.
11 Dec 2024 / 5 min One zod schema per route: Express handler, OpenAPI and TS client With @panth977/routes, each Node.js endpoint is declared once with zod request and response schemas. That one declaration is the typed handler Express serves, the OpenAPI JSON, and a generated TypeScript client. Middleware, plain HTTP and Server-Sent Events, with the code.
8 Dec 2024 / 6 min Zod input and output validation for JavaScript functions TypeScript types vanish at runtime. With @panth977/functions, a function declares zod schemas for its input and output, and a SafeParse wrapper checks them on every call. Wrappers as local middleware, static variables, and a context that carries logs, cleanup and state down the call tree.
7 Dec 2024 / 5 min 10 Javascript tools for clear code design Ten small utilities I reach for to keep JavaScript readable: batching, pub/sub, rate limiting, one-to-many relations, delays, connection strings, and a few others, each with the code.
1 Dec 2024 / 5 min 😰 How is Backend (js) Node.js is probably your backend, and JavaScript gives you far more rope than most people use. A tour of the features that matter on the server, and the ones that quietly hurt.
1 Dec 2024 / 4 min 10 Common Issues in Node.js to keep in Mind Ten mistakes I keep seeing in Node.js code, mostly around promises and validation: floating promises, try without await, unhandled rejections, parsing without zod, and blocking the event loop.