Agents keep working,
even while I sleep

as long as there's a backlog or something to improve —
security included

L1
L2
L3
L4
L5
L6
L7
L8
L9

about me

Konstantin Ryadov

Konstantin Ryadov

Co-founder & CTO of Bulka.AI, an AI copilot for payment operations.

A JVM engineer turned AI engineer: 19 years in payments, then JVM security at Azul, now agents. The SDLC is my life.

blog · podcast · music · github.com/kryadov

where this talk comes from

For clients — what I can't show.
For myself — what I can

For clients: internal products

I build AI agents for my clients' internal products. One public example:

Azul Intelligence Cloud AI Assistant (Sep 23, 2026): ask plain-language questions about Java in production and find where licensing and security risks are hiding. Read-only.

For myself: off the beaten track

In every sense: a different domain (games), a different stack (3D in the browser), different rules (zero infrastructure budget).

Not for profit: no app stores, no ads, no monetization. The games are free.

Everything I show here is open: code, git log, demos.

rules of the experiment

Self-imposed limits: $20 + $100

$20
Claude Pro subscription, limits and all
$100
OpenRouter: GLM, Kimi — open-weight models

Paying for Max is easy. The catch is that then you never learn the one thing that matters.

The question behind it all

For which kinds of tasks does medium effort do as well as x-high?

A budget makes you count: a cheap model and low effort wherever they're good enough, the expensive one only where nothing else will do.

the lay of the land

The L1 → L9 ladder

Levels of AI-assisted development: L1 code by hand, L2 free chats, L3 paid chats, L4 supervised agent, L5 full access, L6 parallel agents, L7 agent team, L8 swarm, L9 ecosystem

Nine levels of AI-assisted development, from Aleksei Litvinau's course “AI-Assisted Engineering”: alekseilitvinau.com/edu

what this talk is about

Three projects, three rungs

L4→L5

Race the City

July 2026

Racing through any city in the world. One agent with full access, a release every half hour.

the bottleneck is me

L5→L6

claude-remote-vm-dev

August 2026

Claude Code sessions on a VM inside the perimeter. They keep going with the laptop closed.

infrastructure for the next rung

L6→L7

itffm 🍄

September 2026

A mushroom forest modeled on a real place. Parallel agents in worktrees, a model for each role.

the bottleneck is review

QR: github.com/kryadov/race-the-cityrepository

rung L4 → L5 · Race the City

Type in a city and drive

  • A low-poly version of a real city: roads, buildings, bridges, rails, water, terrain
  • 19 cars, rivals, time trials, autopilot
  • Traffic, pedestrians, trams, ships, weather, day and night
  • All in the browser, no backend

▶ race-the-city.games

live demo:

Batumi → 🎲 random city → V neon view

Race the City in numbers (git log)

164 releases in the first three days

100
release tags on day one, July 16
435
commits, 360 of them in the first 4 days
28.6k
lines of TypeScript in src/
104
test files (Vitest)

v0.1 → v0.149: 310 tags, and every tag is a deployed build and a GitHub Release.

352 of 435 commits co-authored by Claude Opus. My share: specs, play-tests and decisions.

why this is possible at all

The whole world is source data

Nominatim“Batumi” → coordinates
→
OverpassOSM in a 1 km bbox
→
Terrain TilesAWS elevation, Terrarium format
→
Three.jsmeshes, collisions, road graph
→
IndexedDBthe city, cached

What you get

  • Endless content without level designers
  • Something the agent can work with: a standard, well-documented data format

The catch

  • Overpass answers 429 → 30 s timeout, three mirrors, a stale cache as the fallback
  • Dirty data: water 4 m above the river, bridges with no height

architecture, not agents

OSM + elevation + weather, no server

openstreetmap.orgNominatim, Overpass
AWS Terrain TilesS3, Terrarium PNG
Open-Meteolive weather
→
browserThree.js + IndexedDB, static files on Pages

$0 and zero ops

Nothing to monitor, patch or scale. The CDN takes the load, open APIs serve the data. No infrastructure bill → no need to monetize.

Nothing to leak

No database, no accounts, no secrets. A player's progress stays in their own browser.

Deploy = tag

Rolling back means going to the previous tag. Fork it, and you have your own copy of the game, also for free.

so that it works instead of falling over

The price: you're a guest on someone else's infrastructure

  • Keyless APIs only. A key in a static site is a public key
  • Respect the usage policy. Nominatim: 1 request per second; Overpass answers 429
  • Caching is mandatory. A city loaded once lives on in IndexedDB
  • Mirrors and timeouts. 3 Overpass mirrors, 30 s, a stale cache as the fallback
  • Honest fallbacks. No terrain → flat ground; no OSM → a procedural forest
  • Attribution. OSM data under ODbL, © OpenStreetMap contributors

And a bonus for agents

No server → no migrations, environments or secrets. You can hand the agent the entire release.

Layer boundaries are written down in AGENTS.md: geo/ knows nothing about Three.js, world/ knows nothing about the network.

pace as part of the architecture

A release every ~30 minutes without falling apart

Version = deploy

Every bump is a tag, a Release and a CHANGELOG.md entry marked 👀 “what to check in the play-test”.

boot-check

Tests green, types clean, build passed — and the screen is black. Headless Chrome loads the built app and fails if it doesn't start.

TODO as a living backlog

Play-test → the bug goes in right away → “bugs first, polish later”. No roadmap on paper.

who really wrote the collision code

Where the agent got it wrong — and how we caught it

“An invisible wall in the middle of an ordinary road”
play-test bug report, Paris, Île de la Cité, v0.148.1

  • The agent added a debug readout to the pause screen: solid: quay@1.3m
  • The cause: the quay only had a lower bound. 1593 walls → 25
  • The same class of bug, for the third time

Takeaway

The invariant went straight into TODO: solid ⇒ visible.

The agent doesn't remember the last session. The repo does: AGENTS.md, TODO, CHANGELOG, tests.

the L4 → L5 process

Spec → plan → code → release

brainstorma dialogue: what we build and why
→
specdocs/superpowers/specs
→
plantasks with tests
→
code + TDDagent
→
play-testhuman

Delegated

  • Code, tests, refactoring
  • Releases, CHANGELOG
  • Diagnosing bug reports

Kept for myself

  • What to build, in what order
  • Looking at it with my own eyes
  • When to stop

Bonus: an agent in CI

Comment /oc on an issue or PR → opencode on GLM via OpenRouter, with the same superpowers skills.

why the next rung was needed

The bottleneck: me and my laptop

Race the City commits by hour of day, 435 in total

137 commits between midnight and 7 a.m.

An agent session lives only as long as the laptop is open. Close the lid and the work stops.

Agents should work while I sleep. Not me working alongside them.

QR: github.com/kryadov/claude-remote-vm-devrepository

rung L5 → L6 · claude-remote-vm-dev

Claude Code sessions on a VM inside the perimeter

  • tmux holds every session; systemd + linger survive disconnects and reboots
  • Each session gets its own git worktree and branch, so agents never share an index
  • rd-tui: list sessions, attach, stop, start a new one
  • Pick a provider: Vertex AI, Bedrock, Anthropic API
  • GitLab and GitHub, Enterprise Server included
$ rd-start backend --session new-search
$ rd-start backend --session login-fix \
    --type bugfix
$ rd-start backend --session try \
    --provider bedrock
# close the laptop 💤
$ rd-list --all

github.com/kryadov/claude-remote-vm-dev

why a VM and not just a cloud agent

For corporate development

Perimeter

Code and tokens never leave the company network. The VM is the isolation boundary, so the agent can run docker compose without worry.

Secrets

Provider credentials live in a 0600 file. Only the provider's name goes into tmux, so nothing shows up in ps.

Bedrock gotchas

Without pinned models, the opus alias quietly falls back to a smaller model. WebSearch isn't available there.

One idempotent bootstrap script. Spec on August 15, a working version two weeks later. Built with an agent, too.

QR: commit 1fd1933 in kryadov/race-the-citycommit

“security included”

What to give an agent overnight: npm audit 9 → 0

race-the-city v0.149.1, October 15, 2026, a single commit:

  • 9 vulnerabilities → 0: 2 critical, 3 high, 4 moderate, all in the dev/build toolchain
  • Vite 5 → 8, Vitest 2 → 5: RCE in tinypool, path traversal in @vitest/mocker, a leak in the esbuild dev server
  • A breaking change fixed along the way: Vite 8 builds with Rolldown, manualChunks → codeSplitting
  • boot-check got BOOT_CHECK_PORT so parallel checkouts don't collide

Why it's the perfect overnight task

  • A clear finish line: npm audit = 0
  • A safety net: tests + boot-check
  • Boring for a human, not for an agent

In the CHANGELOG: 👀 “nothing should look different”.

QR: github.com/kryadov/itffmrepository

rung L6 → L7 · itffm 🍄

A quiet walk through a real forest

  • A first-person mushroom-foraging game plus a field guide
  • The forest is built from a real place: the same OSM + Terrain Tiles
  • Birch boletes grow under birches, oyster mushrooms on fallen logs
  • A cabin, a campfire, fishing, quests, a drone, a mine

▶ kryadov.github.io/itffm

Not a single 3D model

data/species/*.yaml
 ├─ morphology → 3D model
 ├─ ecology    → where and when it grows
 └─ name/text  → field guide

A new species is a line of data, not a ticket for a 3D artist.

itffm in numbers (git log)

17 days from spec to v0.103

375
commits, 150 of them on day two
126
release tags, v0.1 → v0.103
57
species in YAML: mushrooms, berries, herbs, finds
109
test files, 25k lines of TS

9 specs, 6 plans. Each spec opens with section 0: “where the code turned out smarter than the spec”.

Carried over from RTC as is: boot-check, CHANGELOG, FEATURES.md, deploy by tag.

side effect #1

“Can we get a bigger map?” → an endless forest

Race the City, v0.92the world is a 2×2 km square around the center, with nothing past the edge
→
players asked“make the radius from the center bigger”
→
itffm, September 10the forest is cut into chunks, walk in any direction

How it got done

A brainstorm in the evening, then 6 hours of autonomous work while I slept. The spec says: any decision not approved before I go to bed, the agent makes conservatively and files as a follow-up instead of guessing.

What came out

If OSM or terrain fails to load for a chunk, it's filled in procedurally from the same seed. No wall, no error on screen.

L6 → L7 in practice · itffm, git log

September 11: one decision, seven branches

06:04plan: 11 play-test bug reports + old TODOs in one batch → my call: in parallel
06:12removed the disclaimer screen that got in the way on mobile
06:22rails sank into the terrain, trees grew through the track
06:25ground seams between chunks
06:27cabin door collision
06:38Esc opens the pause menu
06:42synthesized water sound: you hear the stream before you see it
06:54perf: distance culling

every line after the plan is a merge of its own worktree-agent-<id> branch

My part: one decision

  • gather the reports into one plan
  • see that the tasks are independent
  • say “in parallel”

Claude Code: everything else

  • 7 subagents in a single message
  • 7 worktrees, 7 branches
  • tests in each, 7 merges one at a time

what actually changed between L6 and L7

One primitive — git worktree — and two orchestrators

L6

claude-remote-vm-dev

me → rd-start … --session A
me → rd-start … --session B
me → rd-start … --session C

I wrote the worktree-per-session setup. How many agents, and on what — a human decides.

L7

itffm, Claude Code

me → “in parallel”
agent → Agent(isolation: worktree) ×7
agent → merge ×7

The tool creates the worktrees. How to split the work — the agent decides; I just approve.

Where the agent runs no longer matters:

your own VMtmux + systemd
cloudclaude.ai/code
phonea remote for any of them

the new bottleneck

What tests don't catch

  • Oyster mushrooms rendered as flat pancakes: the generator put the stem in the center
  • Chimeras: a 25 cm cap on a 6 cm stem
  • 243 mushrooms × 5 meshes → a thousand draw calls; even the headless browser froze

The fix is a tool for looking with your own eyes: npm run silhouette-sheet, every species' silhouette on a single sheet.

The bottleneck moved

From “write the code” to “check the result”.

Agents write faster than I can look. Review and visual checks are now the human's main job.

back to the self-imposed limits

Medium or x-high: it depends on the kind of task

kind of taskexamplehypothesis
Executing a plana task from the plan with tests already writtenmedium ≈ x-high, and GLM/Kimi are often enough
More of the sameone more car, one more mushroom species in YAMLmedium ≈ x-high
Diagnosisthe invisible wall on the quay, third time roundx-high pays off
Spec and planendless world, quests, a minex-high and an expensive model

The better the spec and tests, the less effort execution needs. You pay once, at the planning stage.

side effect #2

A screen-shared forest vs. a shouting match

A startup sync. The founders are yelling at each other. Someone shares their screen, and there's a quiet forest: footsteps, birds, a stream, a mushroom under a birch.

The temperature drops.

That wasn't in the spec.

The product lesson

Value shows up where you didn't plan for it. Cheap releases (tag → Pages) let you put a thing in front of people fast and see how they actually use it.

the rungs, side by side

What changed from project to project

Race the Cityremote-vm-devitffm
RungL4 → L5L5 → L6L6 → L7
Agentsone, in my terminalN sessions on a VMsubagents in worktrees + cloud
ModelsOpus for everythingany providerOpus plans, Sonnet executes
MemoryAGENTS.md, TODObranch = sessionCLAUDE.md, specs with section 0
Bottleneckmy sleepthe laptopreview and looking with my own eyes

what you can take to your team tomorrow

Five rules

  • Spec before code. The agent executes a plan. An empty prompt breeds improvisation
  • The contract lives in the repo. AGENTS.md / CLAUDE.md, invariants, known pitfalls. The agent forgets; the repo remembers
  • Check that it boots, not just that tests pass. boot-check catches what green CI misses
  • One agent, one worktree. Without it, parallelism turns into merge conflicts
  • Tools for your eyes. Compress review: contact sheets, readouts, 👀 in the changelog

what's next

L8 and L9: swarm and ecosystem

L5full access
L6parallel
L7I'm here
L8swarm
L9ecosystem

Climbing higher takes not more agents but automated verification: a reviewer agent, visual regression testing, play-testing by bot.

From the backlog

  • Live weather and seasons from real data
  • New OSM layers
  • LAN multiplayer in RTC (the branch already exists)
  • Species photos via ETL in itffm

thank you!

Questions?

QR: github.com/kryadov/race-the-city

🚗 Race the City

kryadov/race-the-city
play: race-the-city.games

QR: github.com/kryadov/itffm

🍄 itffm

kryadov/itffm
play: kryadov.github.io/itffm

Konstantin Ryadov · github.com/kryadov