35 Follager Road, Rugby, United Kingdom
+44 7447675934
office@machinemind.ltd

One business day, one complete product

A complete deployment, not a prototype: from a spec in a Google Doc to a live domain in one working day.

To be clear about the scope: this was the whole chain, not just the code. On 17 September 2026 the spec arrived as a Google Doc at 11:14 in the morning and by the evening the product was live on its own domain. In between we read the specification, built the application, tested it locally, provisioned the production environment on the server (Python virtualenv and dependencies, database and user, file permissions), wrote the Apache vhosts and wired the app through WSGI – the full sysadmin part – deployed it, and then finished by putting the domain in front of search engines: robots rules, a generated sitemap and the Google Search Console verification meta tag live in the page head.

What is live is a cross-platform video catalog with creator profiles, ownership claims, user accounts, a blog, a JSON API, transactional e-mail with DKIM, and a background pipeline that rewrites every description in the creator's own language. Every number below comes from our git history, the production database and the agent session log. Credentials, keys, addresses and private hostnames are redacted.

The numbers

What Value
Spec to live product ~9 working hours (first commit 11:17, production live 20:15)
Working session with the agent 11 h 17 min
Human messages to the agent 104 (~11/hour)
Agent turns (including tool steps) 950
Commits that day (whole workspace) 84
Commits for this product 59
Python written ~9,400 lines
Templates (Jinja/HTML) ~2,350 lines
CSS ~400 lines
Files in the app 93
HTTP routes 99
Production database after day one 14 videos, 6 creator profiles, 3 articles, 156 tags, 25 categories
Model context 547k tokens used of a 1M window, 1 compaction
Prompt cache hit rate 95% (529k tokens cached)
API requests that day 2,246
Tokens through the API 479,858,977 (~480M, of which the vast majority were cache hits)
Real API bill for the day $6.25
Human developers on the critical path 1 (product owner)

What we set out to build

One sentence from the spec: “You add. We promote.” A catalog where a creator pastes a link from YouTube, Shorts, TikTok, Instagram or Facebook Reels, X, Vimeo, Dailymotion or Rumble, and the platform does the rest: real metadata, a real description, a creator profile, a click that goes back to the source platform.

The interesting part was never the feature list. It was the rules the product owner set on the first day:

  • No duplicate content. The description we publish must not be a copy of the source text (search engines punish that). Keep the creator’s original text in the database, publish our own wording, in the source language.
  • Ownership is sticky. An entry belongs to whoever claimed it; only an admin can reassign it.
  • Soft delete only. Hidden rows never leave the database.
  • Rate limits from day one. One video per IP per window, a looser one for confirmed accounts.
  • No secrets in the render path. API keys live server-side, never in a template, never in a JS file, never in an API response.

Those rules created most of the day's work, and most of the day's bugs.

The stack

  • Web: Python 3 + Flask, served by Apache `mod_wsgi` on the production VPS (the trick that matters: `WSGIDaemonProcess` needs `python-home` pointed at the venv, otherwise the daemon quietly uses the system Python and dies with `ModuleNotFoundError: No module named ‘flask’`).
  • Data: MySQL (MariaDB in development), one database per environment, schema migrations as plain SQL files in the repo.
  • Writing: DeepSeek (`deepseek-flash`) through the official API for descriptions, plus a local Gemma 4 12B (LM Studio) for cheap taxonomy calls and as a fallback. Local-first for anything we can run for free.
  • Images: xAI Grok Imagine for the blog covers and in-content illustrations.
  • Ingestion: oEmbed plus careful page scraping for platforms that do not expose a description.
  • E-mail: SMTP with a properly signed domain (DKIM `s=…`, SPF, DMARC) so claim links land in inboxes, not spam.
  • Search: generated `sitemap.xml`, `robots.txt` with a sitemap directive, and the Google verification meta tag.

The environment

None of this ran in a browser tab. The builder worked on a workstation with an RTX GPU, next to the code, with a local 12B model acting as its eyes: every screenshot the agent took was checked by that local vision model before a change was called done. Code was committed locally after every change and pushed to a private backup, then shipped to the public server with `rsync` over SSH – code only, secrets and the virtualenv excluded by policy (a rule we learned the hard way, see below).

The production side is deliberately boring: Apache with `mod_wsgi` running the Flask app inside its own virtualenv, MySQL for the data, a background thread for anything that touches a model, and static assets cached on local disk. Two paid APIs on metered plans (the writing model and the image model), everything else local and free.

env
The environment: a builder workstation with an RTX GPU and a local 12B model doing vision QA, two metered cloud APIs, and a deliberately boring production server.
loop
The loop, repeated all day: request, plan, code, local commit, rsync over SSH, verify on the live URL. About eleven times an hour.

Hour by hour

Times are local (Europe/Warsaw). Commits per hour in brackets.

  • 11:14 The spec arrives, shared as a Google Doc. The clock starts here.
  • 11:17 [7] Landing page and the platform whitelist. A static landing with a premiere countdown goes live on the final domain immediately, so the address is never empty: the marketing page is up while the application is built behind it.
  • 12:00 [8] Flask skeleton: the add wizard, video cards, click logging, the blog blueprint, the JSON API. The local Gemma got beaten into shape (structured output only via `json_schema`).
  • 13:00 [10] The catalog becomes the home page, dedupe by a stable source key, background transcription, SEO copy.
  • 14:00 [3] Creator profiles with avatars, follower counts and a generated “about” pulled from the channel page itself.
  • 16:00 [7] Ownership claims, user accounts, the “my videos” panel, owner editing, the buyer-facing legal pages and the blog posts.
  • 17:00 [9] Language preservation in every prompt (Polish stays Polish), shorter titles and slugs, the first production-grade API surface.
  • 18:00 [3] DeepSeek replaces the local model for descriptions, raw-vs-published text separation, rate limits, a feature flag for local testing. Also the quiet hour: the human takes a break, and the token burn dips with him.
  • 19:00 [7] The add flow goes asynchronous, the progress dialog, the background taxonomy.
  • 20:00 [5] Production deploy: the application replaces the static landing on the domain, thumbnails served locally, robots, sitemap, GSC verification, and three bug fixes straight from the product owner’s live testing.

What actually happened

The human stayed the product owner: he added real videos from his phone, looked at real pages and sent one-line bug reports (“the dialog runs forever”, “the description is a 1:1 copy”, “the request takes too long, it should be ajax”). The agent read the codebase, wrote the migrations, deployed, and then verified on the live server – curl checks, live HTTP status codes, screenshots at 1280×800 reviewed by a local vision model, e-mail headers from a real mailbox, sitemap fetched with a Googlebot user agent.

No hand-off, no “works on my machine”. Every change ended with: deploy → hit the live URL → look at the actual bytes → commit and push.

The five failures that make this honest

1. A `–delete` deploy wiped the production config and virtualenv. The second `rsync` in a two-step deploy had no excludes, so it deleted `config.json` and `venv` on the server. The site was down for a few minutes. Fix: exclude secrets and the venv in every rsync, and test from outside the box (the vhost listens on a specific IP, so `curl` on localhost gives a misleading `000`).

2. We published the model's chain-of-thought as the description. DeepSeek is a reasoning model: with a small `maxtokens` the answer never lands in the `content` field, and our fallback grabbed `reasoningcontent` – so the “description” became the model's internal plan (“We need answer only rewritten description…”). Fix: a token budget large enough for thinking and the answer (6000), JSON output, and never treat reasoning as output.

3. YouTube serves two different page shapes. From one data centre the watch page contained `shortDescription`; from another it contained only the newer `attributedDescription.content`. The scraper looked for the old field, silently fell back to YouTube's generic blurb (“Enjoy the videos and music you love…”), and every rewrite had almost nothing to work with. Fix: read both shapes and reject the generic blurb as if it were empty.

4. Duplicate content was live for ~60 seconds. The add flow published the platform's text immediately and replaced it with our own when the background rewrite finished – so a copy of the source description existed on the public page for about a minute. Fix: keep the raw text in a field that is never rendered, publish nothing until our own text exists, and show a progress dialog in the meantime.

5. The request did the slow work in the foreground. Metadata fetch (1.8 s) plus a local model call for taxonomy (6.5 s) meant ~8.5 s before the server answered – and then a second countdown page. Fix: move the model calls to a background worker and submit the form with `fetch`, so the progress dialog appears instantly and the add takes 1.37 s (a duplicate now takes 0.6 s).

Every one of those was found by using the product, not by writing tests. That is the point of shipping on day one.

How we verified it

  • Live HTTP status checks after every change (home, video cards, wizard, blog, API, feed, sitemap, and the 401/200 behaviour of every admin endpoint).
  • Screenshots at a fixed 1280×800 viewport, reviewed by a local vision model: “GRID: SUBTLE”, “HIERARCHY: OK”, “BOX: OK”.
  • Deliverability proven in real mail headers: DKIM pass, SPF pass, DMARC pass.
  • `sitemap.xml` fetched with a Googlebot user agent, `robots.txt` checked line by line.
  • Rate limits tested by hammering the endpoint twice in a row.
  • Database state inspected directly after every flow (claims, ownership, description sources).

What it cost (the real invoice)

We pulled the numbers straight from the API console for that day – this is the whole build, including every retry, every failed model call and every bug we chased:

Metric Value
API requests 2,246
Tokens 479,858,977
Cost $6.25

Read the shape of that chart too: the burn dips between 17:00 and 19:00. That is not a caching win, that is the human taking a break. No requests, no tokens: even an autonomous loop runs on somebody's attention, and the invoice politely follows the person. The cheapest optimisation we found all day was a nap.

ds
The provider console for 17 September: 2,246 requests, 479,858,977 tokens, $6.25. That is the whole build, retries and failures included.

That is an effective blended rate of roughly $0.013 per million tokens, which sounds impossible until you look at how it was achieved: a cheap high-context model, ~95% prompt-cache hits, and a local 12B model doing everything that did not need to be paid for (taxonomy, channel descriptions, vision QA of our own screenshots).

Would this have been affordable on a frontier model? The same 480M tokens at published list prices (input, no caching, September 2026) would land somewhere around: $144 on a fast budget model, $1,200 on a GPT-class model, $1,440 on a Claude-class model. Prices move and caching changes the maths dramatically, but the order of magnitude is the point: the architecture decision (cheap model + cache + local fallback) is worth roughly two orders of magnitude.

The whole product runs on a handful of dollars of API credit: the expensive part of the day was human attention, not tokens. Prompt caching kept 95% of the context hot; the local Gemma handled everything that could be handled for free; the paid model was reserved for writing that a human would actually read. Code, migrations and the deployment recipe are in version control, so the second product built on this foundation starts on day one at hour nine, not hour one.

The takeaway

A complete product in one business day is not magic and it is not risk-free. It is a narrow spec, a real domain, one repository, no hand-offs, verification on the live server after every change, a human who owns the product decisions, and a few embarrassing failures found early enough to fix the same day.

If you want a working product instead of a slide deck, talk to Machine Mind Ltd.


This case study was written by OpenClaw, an AI agent running on the builder workstation described above, together with DeepSeek – on the same day it happened. It is kept as it was written: a memento of one business day in which a spec, an agent and a human product owner shipped a complete product. Every number in it is measured; the typos are the machine's.