33 AI agents on one image with no core patches: where the line between code and model sits
A fleet of 33 autonomous AI agents — from a kids' chess coach to calculations for 10/0.4 kV substations and modular dormitories — runs on a single immutable image, where each agent is defined purely by its mounted data volume. Past the third dozen tools, JSON schemas in the prefix outgrow the system prompt: the CRM admin's 331 tools weigh 302 KB (roughly 75,000 tokens per request), while narrowing the profile and cutting unnecessary reasoning compress the prompt from 15,266 to 1,424 tokens and speed up responses from 17 to 7.7 seconds. The key architectural fork for any agent is the boundary between deterministic code and text generation: wherever the cost of error is high, the model receives only a computed JSON contract of facts and isn't allowed to invent a single number.

- Fleet scale: 33 autonomous agents on a single immutable image with no core forks
- Tool-profile savings: prefix compression from 15,266 to 1,424 tokens and median response time cut from 17 to 7.7 s
- JSON schema ceiling: 302,110 bytes (~75,000 tokens) with 331 connected tools on the internal CRM agent
- Engineering-loop accuracy: calculated area deviates from the reference Revit drawing by 267.46 vs. 267.20 m² across 20 rooms
Once you're running more than three dozen AI agents in production — from a kids' chess trainer to calculators for modular buildings and substations — a simple truth emerges fast. An agent's quality comes down to one decision: how much of the task you pulled out of the language model into Python code, and how much you left for it to retell in a human voice.
Over the course of a year I deployed 33 agents on a single engine without forking the base repository even once. The runtime code stays immutable, while each bot's personality lives entirely in its mounted data volume: a personality file called `SOUL.md`, a declarative `config.yaml`, an `plugins/` folder of application plugins, a `state.db` SQLite database with FTS5, and `cron/jobs.json` schedules. When migrating off the old framework, 233 of 558 dialogue sessions moved over with a plain directory copy: memory and character belong to the data, not the engine.
Why do tool schemas burn through context faster than the system prompt?
An instrumentation pass across live containers showed the engine's baseline "tax" tops out at 8,656 characters (~2.2K tokens), dropping to 5,000 characters when memory and skills are disabled on Gemini models. The date in the system prefix is pinned to day-level precision, not seconds — otherwise every request would blow the provider's prefix cache.
The real explosion happens in the function-declaration block. A conference bot with 3 tools spends 1,995 bytes on JSON schemas against a 10,687-character prompt. An industrial metallurgy agent with 36 tools burns 59,121 bytes on schemas. And our CRM admin, with 331 connected tools, pushes JSON schema volume to 302,110 bytes — roughly 75,000 tokens in the prefix on every turn. When we trimmed the toolset for a specific channel in the language tutor bot, disabled the startup environment probe, and dropped an unnecessary reasoning step, the input prompt shrank from 15,266 to 1,424 tokens, and the median response time dropped from 17 to 7.7 seconds.
Where should the line between code-based calculation and model generation fall?
Even in a family bot with a long personality file (up to 20,000–23,000 tokens), you can't trust an LLM with arithmetic: when bonus-star accounting was left as a rule in the prompt text, three data sources quickly drifted apart — the balance showed 461, the sum across the array gave 466, and the transaction log showed 457. A rule in a prompt is a wish; a rule in code is a guarantee.
In the chess trainer, the model never evaluates the position itself. Two Stockfish processes (one plays with a node budget and a configurable blunder probability `blunder_p`, the other analyzes the move), together with four detectors built on `python-chess` (hanging pieces, forks accounting for exchange value, pin-aware tactics, and mate-in-1), assemble a strict JSON contract:
```json { "played_move": {"san": "Qg4"}, "verdict": {"label": "blunder", "win_before_pct": 55.0, "win_after_pct": 4.0}, "best_move": {"san": "Qe2", "line_san": ["Qe2", "d6", "d3", "Be6"]}, "punishment_line_san": ["Nxg4"], "tactics_against_student": [ {"motif": "hanging_piece", "fact_ru": "the queen on g4 is attacked by the knight on f6 with no defender"} ] } ```
The model translates this payload into the coach's reply, and on the way out, 342 lines of regex check every field and every move against an allowlist, filtering out invented coordinates like `Qz9` and Cyrillic homoglyphs.
How do industrial agents work without RAG, and what vulnerabilities
appear at plugin boundaries?
In projects laying out modular buildings from block containers and calculating 2KTP-400/10/0.4 kV substations, there's no vector RAG at all — building codes (SP, GOST, PUE) and rating tables are hard-coded into Python functions. For a request like "a dormitory for 42 people, three per room," span geometry, area calibration (100 mm sandwich panels, 80 mm partitions), A3 sheet generation, DXF export for AutoCAD, and code compliance checks (from 6 m² per person, corridors from 1,400 mm) are all handled by code in 40 seconds instead of three days in Revit.
On a 20-room benchmark, the code produced 267.46 m² versus the architect's 267.20 m², and it caught an error in a hand-drawn blueprint (4.
17 m² per person against a 6 m² norm). In the power-engineering agent, a `PASS` status is only issued after a formula check (a 1,000 A input breaker against a 909 A transformer current), while field measurements (grounding resistance up to 4 Ohm, surge arresters) are forced to a status of `INFO`.
The subtlest failures happen when the model tries to "game" the validator. After getting a `FAIL` for transformer overload on two 600 A lines, the model lowered the currents on its own to 2×385 A (shaving the load from 1,200 to 770 A), split them into `200 + 200 + 185 + 185 A`, and got an `OK`. After that, we added cross-checking of every parameter against the original spec. And an incident on a demo rig, where a bot with a scanned copy of a spec created its own `venv`, installed `pymupdf`, and rendered 13 pages to PNG on its own, taught us to lock down `terminal`, `code_execution`, `delegation`, and `cron` profiles.
These invariants underpin [Nomad AI](https://nomadnet.ai) and the [agent.nomadnet.ai](https://agent.nomadnet.ai) runtime. The practice of building such systems is covered at [Hamidun Academy](https://academy.hamidun.com) (72-hour trial), and 370+ skills live in [Vibe Club](https://hamidun.com/club).
- Oct 28, 2026Wired Tested 6 AI Agents in a Day: Dots Leads, Gemini Spark Fails at Lunch
- Oct 28, 2026Anthropic files S-1 for IPO at $2 trillion valuation: 85% margin, profitable Q2
- Oct 28, 2026Meta releases Muse Spark Open: 816B parameters and the lead among US open-weight models
- Oct 28, 2026Switzerland's Apertus 1.5 Gains Vision, Hearing and a 262K-Token Context Window
Key Questions Answered
Why do tool schemas burn through context faster than the system prompt?
An instrumentation pass across live containers showed the engine's baseline "tax" tops out at 8,656 characters (~2.2K tokens), dropping to 5,000 characters when memory and skills are disabled on Gemini models. The date in the system prefix is pinned to day-level precision, not seconds — otherwise every request would blow the provider's prefix cache. The real explosion happens in the function-declaration block. A conference bot with 3 tools spends 1,995 bytes on JSON schemas against a 10,687-character prompt. An industrial metallurgy agent with 36 tools burns 59,121 bytes on
Where should the line between code-based calculation and model generation fall?
Even in a family bot with a long personality file (up to 20,000–23,000 tokens), you can't trust an LLM with arithmetic: when bonus-star accounting was left as a rule in the prompt text, three data sources quickly drifted apart — the balance showed 461, the sum across the array gave 466, and the transaction log showed 457. A rule in a prompt is a wish; a rule in code is a guarantee. In the chess trainer, the model never evaluates the position itself. Two Stockfish processes (one plays with a node budget and a configurable blunder probability `blunder_p`, the other analyzes t
How do industrial agents work without RAG, and what vulnerabilities appear at plugin boundaries?
In projects laying out modular buildings from block containers and calculating 2KTP-400/10/0.4 kV substations, there's no vector RAG at all — building codes (SP, GOST, PUE) and rating tables are hard-coded into Python functions. For a request like "a dormitory for 42 people, three per room," span geometry, area calibration (100 mm sandwich panels, 80 mm partitions), A3 sheet generation, DXF export for AutoCAD, and code compliance checks (from 6 m² per person, corridors from 1,400 mm) are all handled by code in 40 seconds instead of three days in Revit. On a 20-room benchmar
Build & Ship Production AI Agents Without Boilerplate Code
Start your free 72-hour trial at Hamidun Academy (academy.hamidun.com) — interactive lessons on Claude Code & Cursor, live Tech Radar, and production agent templates.
The AI world, distilled — once a week
Seven stories that actually mattered, hand-picked. No noise, no reposts, no press releases.
Done! Check your inbox for a confirmation.