I am looking to join a company where my role leverages my experience in developer relations, and full stack javascript experience, on front-end and backend development. The role will focus on mentoring junior engineers in the modern phase of AI assisted workflows, migrate legacy systems to AI assisted systems, create learning resources (docs, tutorials, videos etc) and leverage my BAU work experience in evolving products to increase revenue, improve performance and decoupling for scalability.
Description: A non-profit life drawing community in Hackney, London — and a production-risk laboratory for exploring emerging technologies, AI automation, and highly decoupled architecture.
Date: 2010-01-07
Tags: resumeRole
Personal Project · Technology PlaygroundFounded 2024 · Hackney, London
Non-profit weekly life drawing community
In 2024 I founded a non-profit life drawing community in Hackney. We meet weekly to practise and improve the fundamentally human skill of life drawing — attention, concentration, and admiration of the figure. In an age of AI-generated imagery, deliberately nurturing the slow, embodied, human skill of observational drawing feels important.
The community is the business. It has real logistics: venues, models, ticketing, payment processing, customer support, marketing, attendance tracking, a growing social following, and a mailing list. It is not a toy — it runs in production, it has real users, and things breaking has real consequences.
That's exactly the point. lifedrawing.art is a deliberate strategy to force continuous learning under production conditions, without commercial risk to an employer.
Every architectural decision is chosen to explore something. The platform is highly decoupled — no monolith, no CMS with a built-in everything — just purpose-fit services wired together with clean interfaces. This creates natural seams where things can be swapped, upgraded, or replaced individually.
The stack is intentionally diverse and evolving. What follows is what it looks like today.
Hosting & delivery
Media & self-hosted infrastructure
Ticketing & payments
Operations & performance management
AI & automation (N8N)
SEO & discoverability
Running a real business — even a small, after-hours one — makes you encounter problems that tutorial projects never surface. Some examples:
The availability of AI tooling, edge computing, and cheap self-hosting has made it genuinely possible for one person to run infrastructure that previously required a small team. lifedrawing.art is my ongoing experiment in what that actually means in practice — not in a sandbox, but against real user expectations, real payments, and a real community that shows up every week.
The answers are usually more interesting than the questions I started with.
Description: Limited company founder, Head of Studio at a DTP newspaper company, and Internet division lead at a printing company in South Africa.
Date: 2010-01-06
Tags: resumeRole
Founder · Studio Lead · Internet Division HeadLondon & South Africa
Before moving into contract freelancing, I built a commercial career that spanned three distinct roles — each one formative in a different way. Together they gave me grounding in business operations, print production, typography and the earliest commercial applications of the web.
Founded and ran a limited company in London with a team of six. Responsibilities spanned business development, client management, production oversight and studio delivery. Running a small company is a crash course in every discipline simultaneously — sales, operations, people management, cashflow and creative quality all compete for the same bandwidth.
This was the period when the web was transitioning from a curiosity to a commercial channel, and the company evolved with it.
Headed the production studio for a small newspaper DTP company. Responsible for the end-to-end production of print publications — from layout and typography through to pre-press output.
This role built a deep understanding of visual hierarchy, layout discipline and the constraints of production at speed — skills that directly inform my eye for UI/UX detail today. My MA in Graphic Design was earned during this period.
Led the Internet division of a printing company in South Africa, building out their digital offering in the early commercial web era. This was genuine frontier territory — the tools, standards and infrastructure were rudimentary, and most of what was needed had to be figured out from first principles.
It was here that I developed the habit of enjoying problems that can't be solved with a Google search.
Print, publishing and early web share a set of disciplines that transfer directly into modern frontend engineering: typography, visual hierarchy, production at deadline, and communicating clearly with clients about technical constraints. That background is why I have always been as comfortable in design conversations as in engineering ones.
Description: Fifteen years as a commercial freelance developer working in London and Barcelona — on-site, remote and hybrid contracts for agencies and household brands.
Date: 2010-01-05
Tags: resumeRole
Senior Frontend Developer**~15 years** · London & Barcelona
Remote, on-site and hybrid contracts
I spent approximately fifteen years as a commercial freelance developer working across London and Barcelona. This period gave me exposure to a huge range of production structures, team cultures, codebases and delivery pressures — from fast-moving digital agencies to enterprise delivery teams serving global brands.
Working freelance built a particular kind of resilience: you become productive quickly in unfamiliar codebases, you learn to communicate technical tradeoffs to non-technical stakeholders, and you develop strong instincts for code quality under deadline pressure.
Contracts included engagements at:
Work delivered for household brands including:
The breadth of clients and codebases across fifteen years means I have rarely been the least experienced person in a room, and I've learned to be productive within days of joining a new team. I've experienced every production culture from cowboy-fast to heavily gated enterprise release cycles, and I understand the practical tradeoffs each imposes.
Working hybrid between London and Barcelona also meant managing client relationships, timezones and communication asynchronously — long before remote-first became standard.
Description: R&D of a real-time screen-sharing Chrome extension for a bespoke remote education platform, using native ES6, WebSocket signalling and WebRTC video streaming on ChromeOS.
Date: 2010-01-04
Tags: resumeRole
Contracted to research and prototype a real-time screen-sharing feature for NetSupport's bespoke remote education platform. The deliverable was a Chrome extension that provided a pseudo-RDP (Remote Desktop Protocol) experience for classroom management on ChromeOS devices.
The project was a focused R&D engagement: assess what was achievable within the Chrome Extension API constraints, design the signalling architecture, and produce a working proof-of-concept.
Chrome Extension architecture
Designed and implemented a Chrome Extension using native ES6 JavaScript, without external frameworks. The extension leveraged the Chrome OS Extension API to capture screen state and stream it in real time — respecting the sandboxed permissions model of the platform.
WebRTC video streaming
Used WebRTC as the video transport layer, establishing peer connections between the teacher console and student devices. Handled ICE candidate negotiation, stream initialisation, and graceful connection teardown within the constraints of the ChromeOS environment.
WebSocket signalling
Built a WebSocket signalling layer to coordinate peer discovery and connection setup between devices on the same network. Designed the message protocol to be minimal, fast, and recoverable on dropped connections.
Research and documentation
Produced technical documentation covering the architecture decisions, limitations of the Chrome Extension API at the time, and a recommended path forward for the production build.
Description: Frontend engineering on Ably's corporate website — migrating a legacy Ruby on Rails codebase to React and Tailwind during a full corporate rebrand.
Date: 2010-01-03
Tags: resumeRole
Joined Ably as a senior frontend engineer on the corporate website team. The project was ambitious: refactor a legacy Ruby on Rails codebase to adopt React and Tailwind CSS while simultaneously rolling out a full rebrand of Ably's corporate identity.
The team operated with a strong culture of paired programming, self-testing and peer review — every PR was reviewed by at least one other engineer before merge, and code was expected to arrive with tests.
After seven months, I transferred laterally to the Developer Relations team to take on the Developer Education role.
React and Tailwind migration
Refactored legacy ERB/Rails view templates to React components styled with Tailwind CSS. This was an active, in-flight rebrand — design and engineering were running in parallel, requiring constant coordination and flexibility as design decisions evolved.
Documentation platform
Heavily involved in the documentation platform, which ran on Nanoc and Textile. Contributed to the architecture of the docs pipeline, improving build times and developer experience for the content team.
Ghost blog and Gatsby CMS
Maintained and extended the Ably engineering blog on Ghost, and worked with a Gatsby-based CMS (backed by Contentful) for structured marketing content.
Paired programming culture
Worked closely with colleagues in daily pair sessions. This reinforced consistent code patterns across the codebase and accelerated onboarding of new engineers.
Description: Lateral transfer from engineering to Developer Relations — creating code-as-content tutorials, producing video content, and building out the Ably YouTube channel.
Date: 2010-01-02
Tags: resumeRole
After seven months as a frontend engineer on the main website, I transferred laterally to the Developer Relations team. The move was driven by a desire to combine my engineering background with teaching — creating content that made Ably's real-time platform accessible to developers at all levels.
The role covered the full content pipeline: designing demos, writing tutorials, shooting and editing video, and managing the public YouTube channel. I also upskilled colleagues in video production and codified the process in an internal policy document.
Code as content
Engineered prototype JavaScript apps as the primary artefact for each piece of content. Each demo was a working application demonstrating a specific Ably feature — WebSockets, presence, history, channels, pub/sub — written cleanly enough to serve as the tutorial code itself.
Blog post tutorials
Wrote developer-facing how-to articles anchored to each prototype. Covered integrations with Netlify Functions, Netlify Identity, Netlify Edge Functions, and various JAMstack static site generators.
Video learning and screencasts
Shot, directed and edited "how-to" screencasts and product learning videos. Managed the full production workflow — scripting, recording with Riverside Studio, editing in DaVinci Resolve and Premiere Pro, and publishing via the YouTube Creator tools.
YouTube channel rebrand and management
Rebranded the Ably YouTube channel. Reviewed and cleaned up the existing catalogue (low quality audio and video), established publishing standards, and took over ongoing channel management.
Video production upskilling
Trained colleagues in basic video editing skills. Wrote the internal video production policy — covering recording standards, file naming, quality thresholds and the review process — to ensure the team could produce content independently and consistently.
Figma + JSON automation
Explored automation of design assets using Figma's plugin API with JSON-driven content pipelines, producing parameterised templates for documentation illustrations and social assets.
Three tutorial videos produced and published on the Ably YouTube channel:
Publish & Subscribe with JavaScript and Ably — An explainer of the pub/sub concept followed by a narrated code demonstration building a simple app with the Ably SDK.
The WebSocket Handbook by Ably — A walkthrough of the Ably WebSocket handbook, covering the protocol, use cases, and how Ably builds on top of it.
Building a realtime quiz app with AWS & Ably — A full tutorial walking through building a realtime quiz application using AWS services and the Ably platform.
Description: Re-architecture of legacy video advertising systems across The Times, TalkSPORT and The Sun, delivering major revenue uplifts and setting the standard for AI engineering practice internally.
Date: 2010-01-01
Tags: resumeRole
Senior AdTech Software EngineerJune 2023 – present · London
The Times, TalkSPORT, The Sun (all News UK titles)
Joined News UK to work on the shared ad-library serving all brands — The Times, TalkSPORT, The Sun and others. The core role is maintaining and evolving the JavaScript ad-delivery product embedded across mobile and desktop web, responsible for all programmatic and direct advertising revenue.
In addition to the engineering work, I became an active voice in the internal AI community — presenting at the All Hands Engineering Meeting, running learning sessions on RAG practices, N8N education, agent hygiene, and harness design.
Active member and presenter in the News UK internal AI community. Contributions include:
Date: 2021-04-13
A Ruby experiment that renders MP3 audiobooks from markdown articles using Google Speech API and Wavenet voices. Web Components power the story selection interface.
Date: 2021-04-13
Use the Chrome extension API to inject a modern UI layer over any legacy ASCII interface — a lightweight approach to enhancing user experience without touching the underlying source.
Date: 2021-04-13
Perlin noise terrain wrapped in both axes with dynamically injected artifacts, giving an infinite impression. Built in PHP and connected to the Instagram API for live content.
Date: 2020-10-23
An ultra-minimal UI that streams huge SVG images over WebSockets — the sketch recreates in real time, line by line, with zero wait. Node.js server hosted on Heroku.
Date: 2021-04-13
Using Blender's Python console to trace chaos algorithms as 3D splines, then converting each spline into a smooth geometry mesh. Pure maths, rendered physical.
Date: 2026-08-31
How to use Netlify Identity and serverless functions to issue Ably JWT tokens to verified users only — keeping your Ably API key hidden and bad actors locked out.
Date: 2021-07-17
A pure CSS parallax effect with minimal scaffolding and zero JavaScript — demonstrated live on CodePen. Simple to drop into any lightweight static site.
Date: 2020-10-23
BASH remote control for the Raspberry Pi Zero camera — JavaScript WebSocket UI with configurable settings and Sunrise/Sunset synchronisation for automated timelapse photography.
Description: Public WhatsApp groups attract spam and bad actors. I replaced ours with an n8n pipeline and a siloed AI chatbot — zero moderation, automatic email escalation when confidence drops.
Date: 2026-08-31
We had a WhatsApp group for lifedrawing.art. It was supposed to be for attendees to ask questions — is the session on this week, what should I bring, where exactly is the venue. Instead it became a part-time moderation job. Spam. Soliciting messages. Promotional posts from people who had never attended. The group number was public-facing and it attracted exactly the people you'd expect.
The moderation overhead was real and it was mine. I killed the group and built a replacement.
A WhatsApp group isn't one thing. It's:
I was only solving problem 1. Questions like "do I need to bring my own easel?" or "is there a session on Bank Holiday Monday?" have definitive answers. They don't need a human. They need a retrieval system with access to the right content.
Problems 2 and 3 I solved differently — email newsletters via Mailchimp for notifications, a Slack workspace for community. Neither involves a public-facing phone number.
n8n is a self-hosted workflow automation tool — think Zapier but open source, running on your own infrastructure, with proper code nodes when you need them. I run it on a VPS via a Cloudflare Tunnel so it's accessible without exposing the host.
The chatbot pipeline: Trigger → Classification → Retrieval → Generation → Confidence check → Response or Escalation
A webhook. I publish a simple web form on the lifedrawing.art site — a text input, a submit button. The form posts to the n8n webhook endpoint. No phone number. No WhatsApp. Anyone with questions uses the form.
The first AI step classifies the question into one of five categories: booking, venue, what-to-bring, model-info, other. I use Claude Haiku — it's a routing task, cheap and fast. The category determines which knowledge source gets retrieved next.
Each category has a corresponding text file — hand-written, kept in a GitHub repo, updated when anything changes. Booking questions get the booking FAQ. Venue questions get the address, transport links, parking info. No vector database. No embeddings. Just the right file for the right question.
This is a deliberate simplification. The knowledge base is small and stable. Full RAG infrastructure would be engineering for its own sake.
Claude Sonnet takes the retrieved content and the original question and generates a conversational response. The system prompt is explicit: answer only from the provided content, do not speculate, do not invent details. If the content doesn't contain the answer, say so.
The prompt also includes the current date and session schedule — injected by n8n from a Google Sheet I update weekly. Sonnet can answer "is there a session this Thursday?" correctly because it has the actual schedule.
Before sending the response, a second AI call (Haiku) evaluates the generated answer against the retrieved content: does this response accurately reflect the source material? It returns a confidence score and a flag: CONFIDENT or UNCERTAIN.
UNCERTAIN triggers escalation.
When confidence is low, the pipeline doesn't send the generated response. It sends me an email with the original question, the generated response, the confidence flag and reasoning, and a reply link. I reply manually. The failure mode is a human — not a confident hallucination.
My initial retrieval step returned the entire FAQ document regardless of category, so the generation step had a lot of irrelevant material to ignore. Sonnet handled it fine but response latency was worse and answers were occasionally unfocused.
Splitting by category and returning only the relevant section cut context to roughly 400 tokens. Response time dropped noticeably. Answers got more precise.
The system handles 40–60 questions per month. Not high volume, but every one of those would have been a notification on my personal phone, often at 11pm.
Building this forced me to write a proper FAQ. Not a vague "here's some info" page but a structured document with explicit questions and explicit answers. That document is now more useful than the chatbot — it's directly searchable on the site and it's what the AI answers from.
The AI didn't replace the knowledge. It made having well-organised knowledge more worthwhile.
The n8n pipeline runs on a £6/month VPS behind a Cloudflare Tunnel. Total infrastructure cost: under £10/month.
Date: 2020-10-23
i3 is my preferred window manager — a lock screen that uses OpenCV and numpy to slice the desktop into animated strips. Developed with iPython, aka Jupyter notebook.
Date: 2021-04-13
Tic-tac-toe with a twist — a multilayer tactical game where players rotate the 3D matrix using Rubik's cube strategy. Built with BabylonJS, React, Redux and ES6.
Description: Engineers have preferred tools, how can we ensure these different AI systems share the most important context? A unified harness built on the AGENT.md convention.
Date: 2026-10-03
TL;DR: Engineers all have their preferred AI tools—some swear by Cursor, others use Claude Code, Copilot, or Aider. How can we design a repository so that no matter which tool a developer brings to the codebase, they all share the same critical context, guardrails, and custom capabilities? The answer is the "AI-Readable Repository" built on the AGENT.md convention and the Model Context Protocol (MCP).
If you're building software in 2026, you aren't just writing code anymore. You're an engineering manager for a diverse, highly capable, but easily confused team of AI agents.
In my project, lifedrawing.art, I recently realized I was suffering from severe AI Tool Fatigue. I had GitHub Copilot acting as my junior dev in the IDE, Claude Code running CLI refactors, and Google Antigravity (AGY) orchestrating complex, multi-agent database migrations.
The problem? Configuration sprawl.
My repo was littered with .cursorrules, .github/copilot-instructions.md, .claude/settings.local.json, and .agents/SYSTEM_DIRECTIVE_GLOBAL.md. Every time my architectural standards changed, I had to update four different rule files.
Here is how I am redesigning my repository to have a single, unified "AI Harness" that any tool—Claude, Aider, Cursor, or AGY—can plug into and share the exact same brain.
.airc (The .bashrc for AI)Just like .bashrc or .zshrc sets up your environment variables, aliases, and $PATH regardless of whether you open iTerm, VS Code's terminal, or SSH into a server—you need an initialization file that configures the AI's "environment" regardless of which LLM or IDE is booting up.
Let's call this the .airc (AI Run Control) file. Here is how that analogy maps perfectly to building a unified harness:
export PATH=... (Shared Tools): In .bashrc, you tell the shell where your tools live. In .airc, you define your MCP (Model Context Protocol) servers, telling the AI: "Here is your PATH to my custom tools. If you need to search the database, the executable is at this local port."source ~/.aliases (Shared Rules): In .bashrc, you source external files to keep things clean. In .airc, you source your context, essentially telling the AI: "Read .ai/guardrails.md for security rules, and .ai/architecture.md for our tech stack conventions.".airc does the same: "You are working on lifedrawing.art. Fetch the current open task from the MCP state server before proceeding."Because there isn't a POSIX standard for AI yet, every tool still looks for its own specific boot file. So how do we actually connect them?
When you first try to solve this DRY (Don't Repeat Yourself) problem, your engineer brain will immediately suggest lateral thinking: Symlinks.
Why not just write your rules in a master file, and then hard-symlink it to the proprietary tools?
ln -s .ai/rc.md .cursorrules
Conceptually, it’s beautiful. Absolute zero-duplication at the filesystem level. But in the real world, it's a trap. Here is why you must disqualify it:
.mdc) files. Claude Code looks for JSON files. If you try to point them all to a master folder using symlinks, Cursor will choke on your Python scripts, and AGY will crash trying to execute Markdown files..cursorrules, the IDE will blindly force those 3,000 tokens of context into every single prompt you type, driving up API costs and diluting the AI's attention.AGENT.mdTo solve this practically, a new standard is emerging in the community: the AGENT.md convention.
When a human developer joins your project, the first thing they read is the README.md. It’s the front door. But for web developers, a better metaphor is index.html. Just as a web server defaults to index.html to know where to load stylesheets and scripts, an AI defaults to AGENT.md. It acts as the physical .airc file for your repo.
To implement this, you hollow out .cursorrules, .github/copilot-instructions.md, and all your other proprietary configs, and replace them with a single text instruction (a "Pointer"):
"You are an AI agent in the repo. You must read
AGENT.mdbefore executing human prompts."
AGENT.md prevents hallucinations)You don't put your entire codebase's documentation inside AGENT.md (that would trigger the Token Tax mentioned above). Instead, AGENT.md acts as a Dispatcher. It tells the AI where to look based on what it is doing, using a concept called Context Tiering:
AGENT.md so the LLM physically cannot ignore them.AGENT.md gives the AI a map: "If you are writing CSS, go read .ai/frontend-rules.md. If you are writing SQL, go read .ai/database.md." The AI only fetches this context when it actually needs it.By using AGENT.md as your router, a human can open the root of your project and instantly understand exactly what constraints the AI is operating under.
One of my biggest bottlenecks was inter-agent communication. I had agents coordinating 40-step database migrations by reading and checking off boxes in a plan.md file.
This works for a solo dev on a weekend, but at enterprise scale, it's a nightmare. Markdown is human-readable, but it's a terrible database for autonomous agents. Concurrent agents will create Git merge conflicts on a markdown table.
The Fix: Wrap your project state in an MCP Server.
Instead of writing to plan.md, connect your agents to a remote source of truth. Run a lightweight local MCP server that interfaces with Linear, Jira, or GitHub Issues.
When Claude or Antigravity needs to know what to do next, they call an MCP tool: get_current_tasks(). When they finish, they call mark_task_complete(taskId).
Because Claude, Cursor, and AGY all natively support MCP, they can now safely read and write to the same state machine without markdown collisions. They see the exact same Kanban board the human team sees.
I wrote a highly specialized Python script called fzfast to help my AI refactor large amounts of code without blowing up its token limit. Initially, this was locked inside my Antigravity .agents/skills/ folder. Copilot and Claude couldn't use it.
To consolidate, you must decouple your AI "skills" from the IDE that runs them.
The modern way to do this is, again, MCP. By wrapping your custom Python scripts or Bash utilities in a standard stdio MCP server, you expose them universally. Add the MCP server to Claude, Cursor, and AGY, and every AI tool on your machine instantly gains the ability to use your custom-built fzfast refactor logic.
Exposing tools via MCP isn't just about sharing code; it's a profound security boundary.
If your AI needs to run a database query, you don't put the database password in the system prompt. You put the password in the local MCP server environment. The AI asks the MCP tool to run the query, and the MCP server executes it securely on the host machine. Secrets never enter the LLM's context window.
If you are moving this framework from a solo project to a multi-developer enterprise environment, you will hit four critical edge cases. A Senior Engineer review of this architecture revealed the following necessary additions to your AGENT.md:
main. You must add a Tier 1 Guardrail explicitly commanding the agent to run git branch --show-current before modifying code..ai/ documentation grows, instructing the agent to "read .ai/02-architecture.md" will eventually trigger massive context-window bloat. Agents must be instructed to use grep or semantic search to extract only relevant sections.We spend so much time making code readable for humans. The next era of software engineering is making repositories readable for AI.
A unified AI harness isn't about picking the "best" AI tool. It’s about structuring your repository so that any AI tool can drop in, read the context via AGENT.md, execute a standard set of custom tools via MCP, and push code safely without breaking your guardrails.
Consolidate your context. Implement Context Tiering. Adopt MCP for state and skills. Your robot team will thank you.
For those reading this as part of a portfolio or hiring conversation, a quick reality check on framing:
This framework is an exercise in lateral thinking, personal tooling, and R&D exploration. It is meant to provoke inquiry into the future of Developer Experience (DevEx), much like a Developer Advocate exploring the bleeding edge of a new paradigm.
It is not a dogmatic mandate, nor is it a deal-maker/breaker for how a team must operate.
In the real world, it is dangerously easy to fall into the trap of "Yak Shaving"—spending 40 hours building a sprawling AI harness just to save 4 hours of coding. Engineering managers rightfully loathe process for the sake of process.
I built this experimental harness out of personal curiosity and necessity while solo-developing a production marketplace (lifedrawing.art). The goal was never to replace coding with configuration, but to explore how we maintain security boundaries and sanity as our toolchains become increasingly fragmented.
At the end of the day, shipping reliable business value is what matters. This harness is simply an exploration of how we might do that a little more elegantly in the AI era.
Ultimately, this architecture serves as a dynamic sandbox. It allows me to rapidly test and adopt emerging AI tools (like Aider, OpenCode, or whatever releases next month) without starting from scratch. By maintaining a common, trusted foundation of skills, MCP servers, and guardrails, the switching cost between tools drops to zero. I can evaluate new agents purely on their capabilities, knowing they are instantly safely bound by the repo's established context.
View the Boilerplate Repository on GitHub ➔
Description: A PWA that keeps a pose countdown in perfect sync across every phone and laptop in the room — built for life drawing sessions. No app install. Just a URL.
Date: 2026-08-31
Life drawing sessions run on time. The tutor sets a pose — five minutes, ten minutes, twenty — and everyone in the room draws until the time is called. If you're running the session from a laptop at the front while twenty people are scattered across a church hall with their easels, keeping everyone synchronised is an underrated logistics problem.
The old solution was a kitchen timer. Or shouting.
I run lifedrawing.art out of Hackney. We regularly have 15–25 attendees across a room that isn't always acoustically friendly. The tutor calls time, people at the back don't hear, someone loses count, someone else loses their nerve and stops too early. The rhythm of a session depends on everyone knowing exactly how much time is left.
The obvious fix is a visible display — a countdown on a screen at the front. Except then you need a dedicated screen at the front, someone to manage it, and it only solves the tutor's view problem not the attendees' individual awareness.
A shared countdown is a solved problem in distributed systems. You emit a tick, everyone listening receives it. WebSockets are built exactly for this.
The architecture is deliberately simple:
START event with the target duration and a server timestamp. Clients compute elapsed time locally from that timestamp — no polling, no drift.The tutor opens the same URL on their phone. They tap Start. Every phone in the room counts down together.
No app install. No account. No App Store approval cycle.
I give attendees the URL at the start of the session. They bookmark it if they like. It works offline — the countdown runs in the client once started, so no server is needed until the next pose begins. On iOS it installs as a home screen app if they want it there.
The Web App Manifest is six lines. The Service Worker caches the shell. The whole thing is smaller than a photograph.
The real engineering work was handling reconnection gracefully. Phones go to sleep. Screens lock. Someone's battery dies and comes back. When a client reconnects mid-pose it needs to catch up to the current state immediately without disrupting the room.
The server always holds the canonical state. On CONNECT it sends the current timer state — duration, start timestamp, paused-at timestamp if paused. The client reconstructs the correct elapsed time from those values. No sync message required. No special handshake. The client does the maths.
const elapsed = Date.now() - startTimestamp - totalPausedMs;
const remaining = duration - elapsed;
That's the entire reconnection strategy.
The current implementation uses a single shared room — everyone who visits the URL joins the same session. That worked for one venue. For multiple simultaneous sessions (we occasionally run parallel workshops) I'd add room codes: Nanoid for the room key, a Map on the server, a hash in the URL.
I'd also add a proper accessibility mode — a pulsing background colour as the timer approaches zero, for anyone at the back who can't read the numerals at distance.
It replaced the kitchen timer on the first session I deployed it. No explanation required. The tutor taps start, everyone's phone counts down. When it reaches zero a gentle chime plays — the same AudioContext tone on every device, triggered by the broadcast event, not the client's own timer, so they all sound within milliseconds of each other.
Twenty artists, one shared beat. That's the whole point.
The stopwatch is deployed at lifedrawing.art. Source code available on request.
Description: Pick the right AI model — capability, context, cost per token. Because throwing Opus at a regex is the engineering equivalent of a sledgehammer on a drawing pin.
Date: 2026-08-31
The thing nobody tells you when you start working with AI agents seriously is that model selection is an engineering decision, not a philosophical one. Pick wrong and you're either burning money on a model that's solving the wrong class of problem, or you're watching a cheap model fail on something that needed proper reasoning, and assuming the whole approach doesn't work.
It does work. You just reached for the wrong tool.
I think about model selection across four axes:
Map any task to those four dimensions and the model choice mostly selects itself.
Tier 1: Frontier reasoning (Claude Opus, GPT-4o, Gemini Ultra)
These are for ambiguous, multi-step problems where intermediate reasoning determines correctness. Code refactors that span multiple files. Architectural design questions. Anything where a wrong intermediate step cascades into a structurally broken output.
Cost: significant. Use sparingly and deliberately.
Tier 2: Fast, capable (Claude Sonnet, GPT-4o-mini)
The workhorse tier. Well-structured tasks with clear inputs and outputs. Writing a test suite for known function signatures. Summarising a document into a fixed schema. Drafting copy from a detailed brief. This is where 80% of your actual agent work lives.
Cost: 5–15× cheaper than Tier 1. Use by default.
Tier 3: High-throughput, low-latency (Claude Haiku, GPT-3.5-turbo class)
Classification, routing, slot-filling, extraction from structured text. If the task is "read this input, output one of these five labels", a frontier model is overkill. Haiku will do it faster and for a fraction of the cost.
Cost: 20–50× cheaper than Tier 1. Use for high-volume repetitive subtasks.
The mistake I see most often — including in my own early pipelines — is using a Tier 1 model to handle tasks that belong to Tier 3, because Tier 1 always succeeds and Tier 3 sometimes doesn't.
That's backwards reasoning. The correct response to a Tier 3 model failing on a task is to improve the prompt and the task specification, not to upgrade the model. A well-structured classification prompt that gives Haiku explicit output format constraints, examples, and a fallback category will outperform a vague Opus prompt on the same task — and cost 40× less.
If you can't make a cheaper model succeed with a better prompt, you may genuinely have a Tier 2 or Tier 1 task. But verify that first.
Context window size and model capability are not the same dimension. A 200k context window doesn't mean you need a frontier model — it means you have a lot of input material. Haiku has a large context window. Use it for RAG retrieval tasks where you're providing a big document and asking for extraction. Use Opus only if the extraction requires sophisticated cross-document reasoning.
In practice, most RAG pipelines are retrieval + formatting tasks. Tier 2 or Tier 3. The embeddings are doing the heavy work. The model is doing finishing work.
For lifedrawing.art's n8n-based AI pipelines:
Opus appears nowhere in that pipeline. The task is well-structured and the inputs are known.
Before you pick a model, do the maths. Sonnet at $3/million input tokens vs Opus at $15/million. If your agent handles 10,000 requests per month at an average of 2,000 tokens each:
For many tasks, Sonnet and Opus produce equivalent outputs. That's £190/month in capability you're not using.
The right question is not "which model is best?" It's "which model is sufficient for this task, at this error rate, at this volume?"
Answer that honestly and the decision is mostly arithmetic.
These observations come from running production AI pipelines at lifedrawing.art and from the AI tooling work I presented at the News UK All Hands Engineering Meeting in early 2025.
Description: WATTPAD is a free platform for readers and writers specicically focused on content for the YA (young adult) demographic. It's social media publishing for young writers. The brief was to design three covers that "stood out" on the list page.


Description: A rebranding of a popular crypto currency portfolio tracker. This project included a full overhaul of the user interface, simplification of UI components, SVG iconography and bespoke user journey that illustrates the steps required for a user to add a new investment to their portfolio.


![]()





Description: A start-up intending to provide select cryptocurrenies as gift cards, which could be purchsed at any POS vending provider. This project required a full brand identity. This included packaging, merchandise, business cards, the website build and a Kickstarter campaign. The products, packaging and vending stands are 3D renders.



## 01 website
















Description: Promotional video for an excersice website that intergrated demonstarted the practice of low-impact excersise. This production required multicamera shoot on a white set, editing, colour grading and sourcing 3rd party music.






Description: Instagram promotional video reels. These include pre-launch announcements, and weekly video blog clips the promote and document a life drawing community in London



Description: Full corporate identity design and conceptualisation, fullstack website engineering with PayPal intergration for ticket purchases, email newsletter design and social media content management solution for a small art community in London









Description: Graphic assets used for a corporate blog post that, in addition to the written content, required a hero banner (according to brand guideline), techical illustration and a bespoke colour scheme for syntax highlighting.



Description: Video tutorial published on YouTube that explains to a developer the concept of Publish/Subscribe (PubSub) by using explanitory narrative, and then teaches the user, with a narated code demonstartion, how to create a simple app.






Description: Marketing video to promote a free dowloadable PDF. This project required script writing, directing of voice over, creating all the video assets, 3D rendering and animation.


Description: User interface design for an online multiplayer 3D tactical dominance game which was inspired by a combination of tic-tac-toe and the Rubik cude.








Description: A branded marketing video to promote a free dowloadable PDF. This project required script writing, sourcng and directing talent, audio edit of voice over, creating the video assets, 3D rendering and animation, editing, color correction and delivery.






Description: Bruce Thomas is a senior front-end engineer in London with 15+ years experience in TypeScript, React, AdTech and developer education. Currently at News Corporation.
Hi. My name is Bruce Thomas. I'm a senior front-end engineer based in London — currently working on video advertising at News Corporation across The Times, TalkSPORT and The Sun. I have a masters degree in Graphic Design which informs how I think about UI/UX, and fifteen-plus years of commercial web development behind me.
Outside of product engineering I'm interested in AI tooling and automation — N8N pipelines, RAG practices, agentic harness design, and the day-to-day craft of working with LLMs. I was invited to present at the News UK All Hands Engineering Meeting in early 2025 on that subject.
My portfolio covers design and video work I'm most proud of. My resume covers the engineering career.
In 2024 I founded lifedrawing.art — a non-profit life drawing community based in Hackney, London. It's also a production-risk laboratory: real users, real consequences, and every emerging technology I want to learn gets deployed there first. Stripe, Eventbrite, Cloudflare Tunnels, self-hosted N8N, Gemini AI, Imgix, JAMstack. It runs itself while I'm at work.
I love abstract and arbitrary photographs — in contrast to vanity shots. There are so many fascinating things in the world more interesting than a posed smile.
here is one of my own (from unsplash)
My lifelong ambition is to write and finish a novel. Over the years I've participated in various writing courses, online competitions and social writing clubs. Some of the stories are published here — the story page is also an experiment in web components.