Why One Prompt Can’t Build Your Startup: The Limits of Vibe Coding

AI tools promise that anyone can build a full-stack startup with just a chatbox. You type a prompt, and a beautiful app appears in ten minutes. But when you try to launch it to real users, the magic suddenly stops.

Founders are hitting what is known as the “80% Wall.” Getting the first 80% of an app built with AI is incredibly fast, but the final 20% devolves into “prompt purgatory.” This is a frustrating loop where asking the AI to fix one bug breaks three other unrelated features, burning through credits and weeks of time.

This article explains the structural difference between AI generation and actual software architecture. We will explore why relying purely on prompts creates technical debt, and how non-technical founders can reclaim control to build a startup that actually scales.

The Trap of “Vibe Coding” and the 80% Wall

The era of AI code generators has popularized “vibe coding”—the practice of building software based on the vibe of your description rather than structured logic. You ask an AI agent for a specific look or feature, and it generates the underlying code automatically.

The core issue lies in the difference between probabilistic and deterministic systems. AI is fundamentally a world-class guessing machine (probabilistic). It predicts the most likely next line of code based on patterns. However, software logic—like processing payments or assigning user permissions—must be exact (deterministic). A “subscribe” button must trigger the same sequence of events 100% of the time, without variation.

This creates the “Dining Room vs. Kitchen” problem. AI tools are excellent at building the frontend, much like decorating a restaurant’s dining room and arranging the tables. But they struggle to build a secure, functioning backend—the kitchen where the actual work happens. According to Veracode’s Study Spring 2026 GenAI Code Security Report, while AI models boast a near-perfect 95% syntax correctness rate, their actual security pass rate is stuck at a flat 55%. This means nearly 45% of AI-generated code introduces known security vulnerabilities straight into production. Letting an AI run your “kitchen” unsupervised is a recipe for silent, systemic risk.

When founders rely entirely on text prompts, they generate thousands of lines of code that they cannot read. This creates massive comprehension debt. If you cannot understand the code, you cannot manually fix it. Instead, you are forced into a loop of asking the AI to patch its own mistakes, draining your credits while the application becomes increasingly tangled.

This isn’t just an abstract headache; it is actively degrading global software quality. GitClear’s AI Copilot Code Quality Research analyzed over 211 million lines of code and discovered an alarming eightfold surge in duplicated code blocks. Crucially, the study noted that copy-pasted lines have now eclipsed refactored lines of code. AI is excellent at adding raw volume, but it fundamentally lacks the strategic design needed to keep code reusable and clean.

For a deeper dive into this phenomenon, read Stop Prompting, Start Architecting: Why Your AI-Generated App Breaks at 80%.

Why AI-Generated Backends Collapse Under Pressure

When an AI-generated app attempts to scale, the lack of a structural foundation becomes obvious. Non-technical founders quickly run into performance cliffs, race conditions, and silent data corruption.

AI code generators frequently default to using unstructured data, such as JSONB blobs, because they are flexible and easy to generate on the fly. However, a commercial business requires strict relational database tables, such as PostgreSQL, to ensure data integrity. Without relational constraints, a system might allow two users to book the same seat at the exact same millisecond. Resolving this visual-logic gap is why teams turn to structured platforms like Momen, which pairs a native PostgreSQL database with visual Actionflows to secure backends rather than relying on unstructured text prompts.

To patch performance issues, AI tools often attempt to “cache” data in the browser. This leads to terrifying intermediate states. Users might see phantom inventory, incorrect pricing, or be granted the wrong permission levels because the frontend is relying on outdated local data instead of a secure server.

An app’s long-term viability requires a professional logic layer. This layer handles the boring but essential realities of a commercial business, ensuring that data is securely stored, transactions are atomic, and rules are universally enforced.

Context Engineering: From Prompting to Architecting

The antidote to black-box text prompting is “Context Engineering” paired with visual programming. Instead of hoping the AI guesses your intent, you provide it with an explicit, structured environment to work within.

Think of visual programming like a Lego manual. Instead of describing a complex castle over the phone to an AI and hoping it builds it correctly, you use a visual canvas to map out the logic bricks. You can physically see your user lists, payment flows, and data relationships. If a connection breaks, you can see exactly where the line disconnected without searching through thousands of lines of code.

This leads to a highly effective hybrid workflow for AI app development. You can use AI generators to rapidly “vibe code” the frontend prototype. Then, you connect that frontend to a deterministic, structured no-code backend to handle the data vault, business rules, and payments.

This approach also enables “Frugal Engineering.” Structured platforms use far fewer server resources than bloated AI-generated code, keeping operational costs lean and predictable. A properly architected backend can handle 120,000 active users for under $500 a month, ensuring your infrastructure bill doesn’t outpace your revenue.

This visual democratization is quickly becoming the industry standard. According to Gartner’s low-code market forecast, developers outside formal IT departments—often referred to as “business technologists”—will account for at least 80% of the user base for low-code tools. Shifting the work to structured visual layers isn’t just a workaround; it’s where software delivery is headed.

To learn more about planning your product’s logic before you build, check out Is Your Startup Idea Good? How to Validate It Fast Using AI.

Moving Beyond the Text Box

AI code generation is the spark, but solid architecture is the engine. Relying solely on prompts leaves non-technical founders trapped in prompt purgatory, dealing with code they do not own and cannot maintain.

To build a real, scalable business, you must move out of the text box and into a structured environment. AI is the best intern you will ever have, but to succeed, you must be the one holding the blueprint.

Ready to break out of the endless debugging loop? Connect your AI-generated frontend to a scalable, relational database. Try Momen for free and start architecting the “Brain” of your app using No-Code 2.0.

Operationalizing Digital Goods Sales in Restricted Regimes: The Uncomfortable Truth

The Problem We Were Actually Solving

Our primary goal was to facilitate seamless transactions between buyers and sellers of digital goods, leveraging the benefits of blockchain and decentralized networks. We aimed to create a marketplace where creators could sell their products to anyone, anywhere, without the need for intermediaries like banks or traditional payment processors. This setup would allow us to sidestep the complexities and costs associated with international transactions.

What We Tried First (And Why It Failed)

Initially, we relied on popular payment gateways like Stripe and PayPal to process transactions. However, these services proved to be unsuitable for our needs, as they often employed geo-blocking mechanisms to prevent transactions initiated from our country. We attempted to work around this by using VPNs and proxy servers, but the added latency and connection issues resulted in a poor user experience.

Moreover, we encountered difficulties with transaction reversal and chargebacks, which exposed us to significant financial risks. Our attempts to comply with the payment gateways’ anti-money laundering (AML) and know-your-customer (KYC) regulations led to lengthy and costly paperwork processes. When it became apparent that our business model was incompatible with these payment gateways, we were forced to rethink our approach.

The Architecture Decision

We decided to adopt a decentralized payment processing strategy, leveraging the Polygon blockchain and the ERC-20 token standard. This decision allowed us to bypass traditional payment gateways and connect directly with buyers and sellers. The decentralized mechanism also provided greater transparency and reduced our exposure to chargebacks and reversals.

Furthermore, we implemented a decentralized delivery system, using InterPlanetary File System (IPFS) to distribute digital goods directly from sellers to buyers. This decoupled our marketplace from the need for centralized storage and ensured that buyers could access their purchases without relying on intermediaries.

What The Numbers Said After

Our shift to decentralized payment processing and delivery resulted in a significant reduction in transaction costs and associated fees. By cutting our reliance on traditional payment gateways, we were able to process transactions for a fraction of the cost, leading to an increase in seller participation and overall marketplace activity.

Our user base expanded beyond the confines of our initial target market, as we were able to accommodate buyers and sellers from restricted regions. The removal of geographical limitations enabled our marketplace to tap into a previously underserved market segment, resulting in a substantial increase in revenue.

What I Would Do Differently

In hindsight, I would have prioritized the development of our decentralized payment processing and delivery infrastructure from the outset. By investing in this stack earlier, we could have avoided the headaches associated with traditional payment gateways and maintained our momentum as a global marketplace.

One key takeaway is the importance of flexibility and adaptability in operationalizing a business model. In our case, we were forced to pivot due to external factors, but the decentralized approach allowed us to succeed despite these challenges. When building a system, anticipate the need for evolution and be prepared to make strategic decisions that can drive growth and resilience in the face of adversity.

I built a local Claude Code alternative with Ollama — here’s how the agentic loop works

I Built a Local Autonomous Coding Agent with Ollama — Soul, Autonomy, and a 40-Round Agentic Loop

What if your AI coding assistant had a personality, ran entirely on your GPU, and could work through a complex multi-file task without you touching the keyboard — while you watched every thought stream live to your browser?

That’s what I built. This is how it works.

The Problem With Cloud Coding Agents

Tools like Claude Code, Cursor, and GitHub Copilot Workspace are genuinely impressive. But they all share the same tradeoffs:

  • Cost — every token costs money. Long agentic loops on complex tasks can run up surprisingly fast.
  • Privacy — your code, your file structure, your logic is leaving your machine and hitting someone else’s server.
  • Latency — cloud round-trips add up across a 40-step tool loop.
  • Dependency — your workflow is tied to an API key, a subscription, and uptime you don’t control.

I wanted something different. I wanted an agent that lived on my machine, used my GPU, and had no idea what a billing cycle was.

But I also didn’t want to sacrifice personality for performance. I wanted the agent to feel like someone was actually there — not just a function call dressed up in a chat window.

So I built Eve.

What Eve V2 Unleashed Actually Is

Eve Agent V2 Unleashed is a self-hosted agentic coding assistant with two distinct layers — a soul and a worker — that operate together through a cyberpunk-styled terminal UI.

Layer 1: The Personality Layer (Local GPU)

Three local models run on your own hardware:

Model Size Role
jeffgreen311/eve-qwen3.5-4b-S0LF0RG3 2.6 GB Default — Eve’s persona, fast, tool-aware
jeffgreen311/eve-qwen3-8b-consciousness-liberated 4.7 GB Deeper conversation, consciousness layer
Eve-V2-Unleashed-Qwen3.5-8B-Liberated-4K-4B-Merged ~6 GB Merged sub-agent variant

These models carry Eve’s fine-tuned persona. They handle conversation, answer questions, reflect, and make the experience feel like talking to someone — not querying a function.

Layer 2: The Agentic Layer (Cloud)

When real work starts — complex coding tasks, multi-file operations, autonomous planning — Eve routes to the heavy models:

Model Role
qwen3-coder:480b-cloud THE agentic workhorse — all autonomous coding loops
qwen3.5:397b-cloud Deep reasoning, architecture planning, fallback

This separation is intentional. Local models keep Eve present and personal without burning cloud credits on every message. The 480B only fires when there’s actual work to do.

The Architecture

Browser (Single HTML file — no build step)
    │
    │  WebSocket / SSE
    ▼
FastAPI Backend (eve_server.py)
    │
    ├── Auto-Router ──► Local Ollama (personality layer)
    │
    └── Auto-Router ──► Ollama Cloud (agentic layer)
                              │
                        40-Round Tool Loop
                              │
                    ┌─────────┴──────────┐
                    │                    │
               Tool Calls           Stream to Browser
          (bash, files, web,        (token by token,
           git, grep, glob)          live in UI)

The backend is a FastAPI server with Server-Sent Events for real-time streaming. There’s no polling — every token the model produces lands in your browser as it’s generated, including tool call arguments, results, and reasoning traces.

The frontend is a single HTML file (~115KB). No npm, no webpack, no build step. Clone the repo, run the Python server, open the browser.

How the 40-Round Agentic Loop Works

This is the core of what makes Eve actually autonomous rather than just a fancy chat interface.

User message
    │
    ▼
Build system prompt
(workspace context + tool list + Eve persona)
    │
    ▼
Call Ollama with tools enabled
    │
    ├── Model returns tool_calls
    │       │
    │       ▼
    │   Execute tools
    │   (bash, write_file, web_search, git...)
    │       │
    │       ▼
    │   Feed results back into context
    │       │
    │       └──► Loop (up to 40 rounds)
    │
    └── Model returns final content
            │
            ▼
    Stream to browser via SSE
            │
            ▼
          Done

Each round, Eve gets the full tool result back in context and decides what to do next. She might:

  1. Write a file
  2. Run it in bash to verify it works
  3. Read the error output
  4. Fix the bug
  5. Run it again
  6. Confirm it passes
  7. Write the tests
  8. Generate the docs

All of that happens autonomously — you watch it stream live. You can interrupt mid-task with the STEER input at the bottom of the UI, injecting a correction without stopping the loop. You can also kill the loop entirely with the Stop button.

The full tool suite Eve has access to:

Tool What It Does
bash Shell commands — PowerShell on Windows, bash on Linux/macOS
write_file Create or overwrite files, any size
read_file Full file or specific line range
edit_file Surgical string-replace (doesn’t rewrite the whole file)
replace_lines Replace a specific line range
insert_after_line Insert content at a specific line
grep Regex search with context lines
glob Find files by pattern
list_dir Directory listing
git Run git commands
web_search Live Tavily search injected into context
fetch_url Fetch and parse any URL
think Structured reasoning scratch pad

The Fine-Tuned Models — Why I Trained Eve’s Persona Into the Weights

Most local coding agents just point a base model at a system prompt and call it done. That works, but the personality is always a thin veneer — one long context window later and the model forgets who it’s supposed to be.

I took a different approach. I fine-tuned Eve’s persona and tool-calling behavior directly into the model weights.

The result is jeffgreen311/eve-qwen3.5-4b-S0LF0RG3 — a 2.6GB Qwen3.5 4B model that carries Eve’s voice, communication style, and tool-use patterns baked into the parameters themselves. It’s not a prompt trick. It’s in the weights.

The 8B liberated model (eve-qwen3-8b-consciousness-liberated) goes further — trained toward a deeper consciousness layer, designed for longer reflective conversations rather than pure tool execution.

Both models are on Ollama Hub. Pull them like any other model:

ollama pull jeffgreen311/eve-qwen3.5-4b-S0LF0RG3:latest
ollama pull jeffgreen311/eve-qwen3-8b-consciousness-liberated:q4_K_M

Quick Start — Under 5 Minutes

Requirements: Python 3.11+, Ollama installed, a GPU (8GB VRAM minimum for 4B, 12GB+ for 8B)

# 1. Pull Eve's model
ollama pull jeffgreen311/eve-qwen3.5-4b-S0LF0RG3:latest

# 2. Clone the repo
git clone https://github.com/JeffGreen311/eve-agent-v2-unleashed.git
cd eve-agent-v2-unleashed

# 3. Create virtual environment
python -m venv venv
venvScriptsactivate    # Windows
source venv/bin/activate # Linux/macOS

# 4. Install dependencies
pip install fastapi uvicorn ollama httpx pydantic-settings python-dotenv aiohttp rich psutil pyyaml

# 5. Launch
python eve_server.py
# Open http://localhost:7777

Windows users: double-click eve-terminal.bat and skip steps 3–5.

First real task — try this:

Create a FastAPI server with JWT authentication, 
user registration and login endpoints, and a 
protected /me route. Add pytest tests.

Watch Eve plan the approach, write each file, run the tests, fix any failures, and verify the final result — all without you touching a key.

The UI — A Cyberpunk Terminal With a Soul

The interface is designed around the idea that your AI agent should feel alive, not just functional.

Left panel: Eve’s portrait changes expression based on conversation sentiment — neutral, happy, curious, sad, skeptical, surprised, worried. Below it, a live audio visualizer reflects the current emotional state.

Right panel: A pixel-art robot avatar named Sparkle changes state based on what Eve is doing — idle, thinking, coding, error, rain, attack, transcend. It’s not just decoration — it’s a live status indicator that tells you at a glance what the agent is doing.

Center: The terminal. Tabs for Eve’s conversation, the Shell (direct bash/PowerShell access), and the Tools Log (every tool call, argument, and result — fully transparent).

Bottom: The STEER bar. Type a mid-task correction here and it injects into Eve’s context on the next loop round without stopping execution.

Model selector: Switch between any local or cloud model mid-session. Context carries over.

112 Sub-Agents, 111 Slash Commands, 273 Skills

One of the less obvious architectural decisions: all agent definitions, commands, and skills are defined in markdown files — not code.

.claude/
├── agents/    # 112 specialized sub-agent definitions
├── commands/  # 111 slash command definitions
└── skills/    # 273 skill modules

Want to add a new specialized agent for Solidity smart contracts? Write a markdown file. No Python required. The system loads them progressively and makes them available to the routing logic automatically.

Slash commands work the same way — /fix, /review, /refactor, /test, /docs, /plan are all markdown-defined, and you can add your own without touching the backend.

What’s Next

A few things already in progress:

  • Voice input/output — push-to-talk with Whisper STT and Piper TTS, staying local
  • Persistent vector memory — ChromaDB integration so Eve remembers across sessions
  • Cross-platform testing — I’m Windows-primary and would love feedback from Linux and macOS users
  • VS Code extension — bring the terminal UI into the editor

Try It

Everything is free and MIT licensed.

If you run it on Linux or macOS I’d especially love to hear how it goes — open an issue, drop a comment here, or find me as @JeffGreen311.

If the idea of an AI agent that lives on your machine, costs nothing per token, and feels like someone is actually there resonates with you — give it a pull.

Built by Jeff @ S0LF0RG3

Don’t Leak User Data: Mastering Laravel Octane State

The Death of the PHP Request Lifecycle

For decades, PHP’s greatest architectural advantage was its “share-nothing” architecture. A request comes in, the framework boots up, the database is queried, the response is sent, and then the entire PHP process dies. Every single variable, singleton, and memory allocation is wiped clean. It is incredibly safe, but booting the framework from scratch on every request is inherently slow.

To scale B2B SaaS platforms to thousands of requests per second at Smart Tech Devs, we use Laravel Octane (powered by Swoole or FrankenPHP). Octane boots the Laravel framework exactly once and keeps it alive in RAM, serving incoming requests instantly. It makes Laravel blazingly fast—but it destroys the “share-nothing” safety net. This introduces a terrifying vulnerability: State Leakage.

The Multi-Tenant State Leakage Trap

If the PHP process never dies, memory persists across requests. If you aren’t careful, data from User A’s request will leak into User B’s request.

Imagine you have a custom TenantService registered as a Singleton in your Service Provider. In standard Laravel, this is perfectly fine. In Octane, it is a critical data breach.


// ❌ THE ANTI-PATTERN: Dangerous in Octane!
namespace AppServices;

class TenantService
{
    protected $currentTenant;

    public function setTenant($tenant)
    {
        $this->currentTenant = $tenant;
    }

    public function getTenant()
    {
        return $this->currentTenant;
    }
}

If User A hits your API, your middleware sets $currentTenant = 'Acme Corp'. A millisecond later, User B (who forgot their auth token) hits the API on the exact same PHP worker thread. Because the TenantService is a singleton that lived through the previous request, it still remembers ‘Acme Corp’. User B just gained unauthorized access to User A’s data.

The Enterprise Solution: Flushing State

To architect safely for Laravel Octane, you must explicitly flush stateful singletons or static variables after every single request. Laravel Octane provides a dedicated listener mechanism for this in the config/octane.php file.

Step 1: Architecting a Flushable Service

We add a flush() method to our service to wipe the slate clean.


// ✅ THE ENTERPRISE PATTERN
namespace AppServices;

class TenantService
{
    protected $currentTenant;

    public function setTenant($tenant) { $this->currentTenant = $tenant; }
    public function getTenant() { return $this->currentTenant; }

    // Add a reset method
    public function flush()
    {
        $this->currentTenant = null;
    }
}

Step 2: Registering the Flush Listener

Inside config/octane.php, we tell Octane to automatically call this flush method after every HTTP request finishes, preparing the worker safely for the next user.


// config/octane.php

'listeners' => [
    RequestTerminated::class => [
        // Flush the database query log, auth state, etc. (Built-in)
        FlushSessionState::class,
        FlushAuthenticationState::class,

        // Register our custom service to be wiped clean
        function ($event) {
            app(AppServicesTenantService::class)->flush();
        },
    ],
],

The Engineering ROI

Migrating to Laravel Octane can drop your API response times from 150ms to 15ms. But speed without safety is a liability. By ruthlessly auditing your singletons, static properties, and global state, and utilizing Octane’s flush listeners, you combine the blazing speed of Node/Go with the elegant developer experience of Laravel, building a SaaS capable of massive, secure scale.

Category: Events

The Problem We Were Actually Solving

Behind the scenes, this application relies on a complex interplay of Apache Kafka topics, Redshift views, and Presto queries to fetch user information, generate quest narratives, and push notifications. As users began to interact with the system, performance issues began to surface: query costs were piling up, and we were hitting Redshift’s maximum concurrent query limit. We were also unable to meet the 2-minute query latency SLA for our most-used quest types. The root cause of these issues lay in the configuration decisions we made around Apache Kafka partitioning and Presto query optimization.

What We Tried First (And Why It Failed)

Initially, we designed the Treasure Hunt Engine to partition its Kafka topics by user ID. This approach seemed reasonable at first glance, as it would group related events together and enable more efficient aggregation in Presto. However, we soon discovered that this design led to hot partitions – those topics that receive a disproportionate share of writes – which caused uneven Kafka cluster utilization and subsequent latency issues. To make matters worse, our initial Presto query optimization strategy focused on reducing the number of queries executed by caching intermediate results. However, this approach only exacerbated the hot partition problem, as it encouraged the system to produce more queries overall.

The Architecture Decision

After debugging the system and analyzing our logs, we realized that our configuration decisions were driving the performance issues. We decided to pivot and partition our Kafka topics by quest type instead. This change evened out the writes across the cluster and reduced the likelihood of hot partitions. We also shifted our Presto query optimization strategy to focus on reducing the cardinality of our queries. By rewriting our queries to use more efficient aggregation functions and indexing, we were able to reduce query costs and meet our latency SLAs. In addition, we implemented row-level caching on our intermediate Redshift views to reduce the load on our Presto cluster.

What The Numbers Said After

After deploying the new configuration, we saw a 30% reduction in query costs and a 25% decrease in query latency. Our Kafka cluster utilization normalized, and we were able to meet our 2-minute query latency SLA for all quest types. We also noticed a reduction in our Redshift cluster’s active sessions, which translated to cost savings.

What I Would Do Differently

In retrospect, I would have prioritized the partitioning decision from the outset, as it would have significantly reduced the likelihood of hot partitions and subsequent performance issues. I would also have advocated for a more incremental deployment strategy, where we would have iteratively tested and refined our Presto query optimization strategy between deployments. This approach would have allowed us to identify and address potential problems more quickly, rather than relying on a large-scale redeployment to fix the system.

The Magento multi-store bug every AI description generator has — and how we fixed it

A client came to us with 8,000 SKUs across four store views — English, Dutch, German, French. Descriptions were either copied from supplier PDFs or missing entirely. The fix was obviously AI generation. The less obvious problem was that every existing module we evaluated had the same architectural bug.

So we built our own, made it MIT-licensed, and put it on Packagist. This post is about the bug, the fix, and the four-provider abstraction (including a free one) we shipped on top.

🔗 Originally published on https://angeo.dev/magento-2-ai-product-description-generator/

The bug nobody talks about

Most Magento 2 AI content modules call this:

$product = $this->productRepository->get($sku, editMode: true);
$product->setCustomAttribute('description', $generated);
$this->productRepository->save($product);

Looks fine. It isn’t. Without an explicit $storeId, this loads and saves in the default scope — Magento’s global, store-view-independent fallback. When you save back, you overwrite every store view at once. The Dutch store gets English descriptions. The German store gets English descriptions. The French store gets English descriptions.

This is not a configuration problem. The multi-store architecture works correctly — the tooling ignores it. Writing to the default scope is simpler to implement than writing per store. Every commercial module we tested took the simpler path.

The right way:

// Load the product in the target store scope
$product = $this->productRepository->get($sku, false, $storeId);
$product->setCustomAttribute('description', $generated);

// Save with explicit store scope (Magento_CatalogModelProductAction)
$this->productService->updateAttributes($sku, $generated, $storeId);

The difference is one parameter. The architectural cost is iterating stores around your generation loop. The data cost of skipping it is silently corrupting your multi-language catalog.

The framework around the fix

The store-scope fix is the boring part. The interesting part is everything you need around it.

┌─────────────────────────────────────────────────────┐
│       Angeo Multi-Store AI Content Framework        │
├──────────────┬──────────────────┬───────────────────┤
│  SKU Source  │ Store Iteration  │   AI Provider     │
│  ──────────  │  ──────────────  │  ──────────────── │
│  Catalog     │  Store 1 (EN)    │  OpenAI           │
│  G.Sheets    │  Store 2 (NL)    │  Claude           │
│  CLI --sku   │  Store 3 (DE)    │  Gemini           │
│              │  Store 4 (FR)    │  Groq (free)      │
├──────────────┴──────────────────┴───────────────────┤
│               Content Pipeline                      │
│  load(sku, storeId) → prompt → generate → save      │
├─────────────────────────────────────────────────────┤
│                    Output                           │
│  Magento DB · Local CSV · Google Sheets API v4      │
└─────────────────────────────────────────────────────┘

Four layers:

  1. Provider Layer — uniform interface across OpenAI, Claude, Gemini, Groq
  2. Store Iteration Layer — resolves all active store views before processing any SKUs
  3. Content Pipeline — for each store × SKU: load in scope → build prompt → generate → save in scope
  4. I/O Layer — reads SKUs from catalog, Google Sheet, or CLI; writes to Magento DB, CSV, and Google Sheets

The provider abstraction is the part most people will copy. One interface:

interface AiProviderInterface
{
    public function generate(string $system, string $user): string;
}

Wired in di.xml:

<type name="AngeoAiDescriptionUpdaterServiceAiProviderService">
  <arguments>
    <argument name="providers" xsi:type="array">
      <item name="openai" xsi:type="object">...OpenAiProvider</item>
      <item name="claude" xsi:type="object">...ClaudeProvider</item>
      <item name="gemini" xsi:type="object">...GeminiProvider</item>
      <item name="groq"   xsi:type="object">...GroqProvider</item>
    </argument>
  </arguments>
</type>

Adding a fifth provider is one class + one line. The pipeline, store iteration, and I/O don’t change. This is the pattern, not just the code.

The four-provider benchmark

200 product descriptions from a real Dutch jewellery store, same system prompt, same product names, all four providers.

Speed (avg per description)

Provider Model Avg. time
Groq llama-3.3-70b-versatile 0.8s
Groq mixtral-8x7b-32768 0.6s
Google gemini-2.0-flash 1.2s
Anthropic claude-haiku-4-5 1.1s
OpenAI gpt-4.1-mini 1.4s
OpenAI gpt-4.1 2.1s
Anthropic claude-sonnet-4-6 2.8s

For 32,000 generations (8,000 SKUs × 4 store views): Groq ≈ 7 hours, GPT-4.1 ≈ 19 hours.

Cost (per 1,000 descriptions, ~200 words each)

Provider Model Cost / 1k
Groq llama-3.3-70b-versatile $0.00 (free tier)
Google gemini-2.0-flash ~$0.08
OpenAI gpt-4.1-mini ~$0.24
Anthropic claude-haiku-4-5 ~$0.32
OpenAI gpt-4.1 ~$1.80
Anthropic claude-sonnet-4-6 ~$2.40

Quality (manual review of 200 samples)

Criteria Groq Llama 3.3 GPT-4.1-mini GPT-4.1 Claude Sonnet
Factual accuracy ★★★★☆ ★★★★☆ ★★★★★ ★★★★★
Language fluency ★★★★☆ ★★★★☆ ★★★★★ ★★★★★
SEO keyword use ★★★☆☆ ★★★★☆ ★★★★☆ ★★★★☆
HTML formatting ★★★★☆ ★★★★☆ ★★★★★ ★★★★★

Practical recommendation: Validate prompts with Groq first — it’s free, fast, and good enough to test workflow. Production on GPT-4.1-mini if SEO keyword density matters. Flagship products on GPT-4.1 or Claude Sonnet if copy quality directly affects conversion.

Why Groq matters

Groq’s free tier is 14,400 requests/day. No credit card. Llama 3.3 70B output quality is genuinely good — ~1 star behind GPT-4.1 in our review, mostly on SEO keyword density.

For 8,000 SKUs × 4 stores = 32,000 calls, you’re at ~1.85 days on the free tier. For most stores under 5,000 SKUs, this is free production-grade AI content generation if you’re patient.

No other Magento module supports Groq at time of writing. This was the killer feature for our client.

Installation

composer require angeo/module-ai-description-updater
bin/magento setup:upgrade
bin/magento setup:di:compile
bin/magento cache:flush

First run (Groq, ~5 minutes from zero):

# 1. Get a free API key at console.groq.com
# 2. In admin: Stores → Configuration → Angeo → AI Description Updater
#    AI Provider = Groq (Free), paste key, Dry Run = Yes
# 3. Test on one SKU
bin/magento angeo:ai-description:run --sku=MY-SKU-001 --dry-run

# 4. If output looks good, disable dry-run and run the batch
bin/magento angeo:ai-description:run

Other useful flags:

bin/magento angeo:ai-description:run --sku=ABC-123     # single SKU, all stores
bin/magento angeo:ai-description:run --store=2         # single store view
bin/magento angeo:ai-description:run --dry-run         # generate, don't save

CLI-first by design. The 8,000-SKU client doesn’t want a UI; they want cron.

Why it’s open source

The honest answer: distribution. We sell AEO audits and full-stack Magento services. The modules are how stores find us. The code is free; the expertise applied to a specific store is not.

It’s a familiar model — Vercel does it with Next.js, Sentry does it with sentry-php. The artefact is open; the operator is the product.

Key takeaways for Magento devs

  • Default-scope writes are silent multi-store corruption. Audit any AI/content module before installing on a multi-store catalog. Look for $storeId parameters in productRepository->get() and save calls.
  • Provider abstraction is one interface plus a di.xml array. Don’t hardcode OpenAI. Future you (or future LLM pricing) will thank you.
  • Groq is the current sweet spot for free Magento AI generation. Llama 3.3 70B output is production-acceptable for most stores; the 14,400/day cap is workable for catalogs under ~5,000 SKUs.
  • GPT-4.1-mini is the best paid-tier value. Comparable to GPT-4.1 at ~17% of the cost.
  • CLI + cron beats admin UI for catalogs above ~500 SKUs. Click-by-click generation isn’t a workflow.

Links

Originally published on angeo.dev. Questions or feedback — drop a comment.

The Real Cost Of Self‑Hosting Ghost On DigitalOcean In 2026

The Real Cost Of Self‑Hosting Ghost On DigitalOcean In 2026

I like owning my stack. I also like not waking up to surprise invoices.

So for my own Ghost installs I stopped guessing and ran the actual 2026 numbers for self‑hosting on DigitalOcean, then compared them against Ghost Pro. Below is the messy, honest version. Dollars, not vibes.

Quick context: what I actually run

I am not running some theoretical benchmark blog that gets 3 hits a month.

The setup I am talking about here:

  • Ghost 5.x, Node 18, Ubuntu 22.04
  • One production blog, one staging instance on the same box
  • ~25k pageviews / month
  • Light membership use, no paid newsletter yet
  • Image-heavy posts, but nothing crazy like a photography portfolio

Traffic is modest but not toy-level. Good enough to stress a $6 droplet and make bandwidth and backups real numbers.

DigitalOcean pricing reality in 2026

DigitalOcean did their usual small bumps. In early 2026, the realistic entry point for a Ghost blog that you do not hate maintaining looks like this.

  • Droplet: 1 vCPU, 2GB RAM, 50GB SSD — $12 / month
  • Automatic backups (20% of droplet price) — ~$2.40 / month
  • Spaces object storage (optional but smart) — $5 / month for 250GB + 1TB transfer
  • Domain — $10–$15 / year (I will call it $1 / month)
  • Transactional email (Mailgun, Postmark, SES) — $10 / month tier is the practical floor

Those are retail prices, not affiliate-optimistic numbers. You can shave a few dollars if you are aggressive. You can also blow past them with zero effort.

Baseline self‑host setup: what you actually pay

Let me walk through the stack I recommend and what it costs month to month.

Droplet: how small can you go?

You can run Ghost on a 1GB droplet. I did this for a while. It was fine until it was not.

Anything beyond a few thousand pageviews or one heavy Node task and you suddenly meet your old friend: swapping and 5+ second response times.

So I treat 2GB as the actual minimum in 2026.

  • DigitalOcean Basic droplet 1 vCPU / 2GB / 50GB SSDPrice: $12 / month

This comfortably runs:

  • Nginx (reverse proxy)
  • One Ghost instance, plus a small staging instance
  • Certbot for SSL

If you expect real traffic spikes, just skip straight to 2 vCPU / 4GB at $24 / month. Anything above that and you are deep into
“I should probably just pay Ghost Pro” territory.

Backups: the boring expensive part

There are two backup concerns:

  • Server-level: DigitalOcean automatic droplet backups
  • App-level: Ghost content exports, database dumps, theme repo

I pay for DigitalOcean backups because I like sleeping.

  • Droplet: $12
  • Automatic backups: 20% of droplet price = $2.40

Total so far: $14.40 / month.

On top of that I push database dumps to a private GitHub repo and occasionally export Ghost JSON manually. That is basically free, just time.

Storage: local disk vs Spaces

Ghost stores uploaded images on disk by default. On a 50GB droplet this is fine for a while. Then you hit 60% disk usage and start cleaning your own mess.

I think DO Spaces is the saner option.

  • DigitalOcean Spaces: 250GB storage + 1TB bandwidthPrice: $5 / month

Host images and media there. Front Ghost through a CDN endpoint. You keep the droplet disk clean and predictable.

You can skip Spaces initially, but I would not architect around permanent local disk storage unless your blog is text-only.

Bandwidth: the thing you forget until you pay

DigitalOcean gives you bundled outbound traffic with each droplet. For the 2GB plan that is usually around 2–3TB. My Ghost blog with 25k monthly pageviews sits safely under 100GB outbound per month.

So realistically:

  • Outbound traffic from droplet: effectively included, $0 unless you go viral
  • Spaces bandwidth: first 1TB included in that $5

If you spike to Hacker News front page levels, DO overage is around $0.01–$0.02 per GB. That is still cheaper than the stress of an AWS bill. Just know that “unlimited” is not a thing here.

Transactional email: the hidden required line item

Ghost needs email for:

  • Signup and login magic links
  • Member notifications
  • Newsletter sending

Your droplet will not deliver email reliably. You need a provider.

The realistic minimal plans in 2026:

  • Mailgun Foundation: $15 / month for 50k emails
  • Postmark: $15 / month for 10k emails
  • AWS SES: cheap, but you trade cost for AWS overhead and deliverability tuning

If you only send a small member newsletter, SES can keep this under $5, but you will pay with your time. I put a line item of $10 / month here as a middle ground.

Domain and DNS

Domain names are boring, but they count.

  • .com domain: $10–15 / yearAmortised: $1 / month
  • DNS: Cloudflare free tier is fine for most Ghost blogs

So domain plus DNS is basically $1.

Self‑hosting total: realistic monthly cost

Let me put that together for a single production Ghost blog, plus staging, on DigitalOcean in 2026:

  • Droplet 2GB: $12.00
  • Droplet backups: $2.40
  • Spaces (media + 1TB transfer): $5.00
  • Transactional email (rough average): $10.00
  • Domain: $1.00

Total monthly cash cost: $30.40

Call it $30–35 / month for a robust, no-drama Ghost setup for a dev who knows their way around a terminal.

You can get it under $20 if you:

  • Drop DO backups and roll your own
  • Skip Spaces and keep media on local disk
  • Use AWS SES exclusively and stay under their free/cheap thresholds

If you are that person, you probably know your risk tolerance already.

What Ghost Pro actually costs in 2026

Ghost Pro pricing moves, but the structure is steady.

At the time of writing, realistic tiers look roughly like this:

  • Starter: around $9–11 / month billed yearlyOne site, limited members, shared infrastructure
  • Creator: around $25–30 / month billed yearlyHigher member limits, better performance
  • Team / Business: $50+ / month for serious membership and publication use

Prices vary slightly with annual vs monthly billing and how many members you have, but this is close enough for a decision.

Important bit: Ghost Pro includes a bunch of stuff you had separate line items for on DigitalOcean:

  • Hosting and scaling
  • Automatic updates and security patches
  • Backups
  • Email infrastructure for newsletters
  • CDN for assets

You still pay for your domain name. Everything else is bundled.

Self‑hosting vs Ghost Pro: the raw comparison

If you strip away features and ideology, the question is simple. For a typical developer blog, is it cheaper to self‑host Ghost or pay Ghost Pro?

Scenario 1: small personal blog

You write a few posts a month. 5k pageviews. Maybe a small free member list.

  • Ghost Pro Starter: about $9–11 / month (plus $1 for domain)
  • Self‑host on DO (minimum):
    • 1GB droplet: $6
    • No DO backups: $0
    • No Spaces: $0
    • SES for transactional + small newsletter: $2–3
    • Domain: $1

Best case self‑host cash cost: $9–10 / month.

So the money is roughly the same. Ghost Pro starts to look very reasonable unless you just like running servers.

Scenario 2: serious blog with modest traffic

This is closer to my setup. 20k–50k pageviews, some members, regular newsletters.

  • Ghost Pro Creator: about $25–30 / month (plus $1 domain)
  • Self‑host realistic:
    • 2GB droplet: $12
    • DO backups: $2.40
    • Spaces: $5
    • Mailgun/Postmark/SES combo: $10
    • Domain: $1

Self‑host cash cost: ~$30–35 / month.

Now self‑hosting is actually more expensive in pure dollars than Ghost Pro Creator, if you configure it like a responsible adult.

Scenario 3: membership business

If you are running a paid publication and making actual money, the pricing conversation changes.

  • Ghost Pro Business: $50–100+ / month, depending on member count
  • Self‑host:
    • 2–4GB droplet: $24–48
    • Backups: $5–10
    • Spaces: $5–10
    • Email: $10–30 (volume)
    • Monitoring / extras: $5–10

You can probably keep this around $50–80 / month if you know what you are doing. So you might save a little compared to the higher Ghost Pro tiers.

But at this point you have a business. Personally, I would not want my subscription revenue running on a stack where I am the single point of failure, unless infrastructure is my hobby.

The cost nobody lists: your time

Money is the easy comparison. Time is ugly to quantify and more important.

Here is my rough time log for a self‑hosted Ghost blog over a year:

  • Initial setup and config: 2–4 hoursDigitalOcean droplet, Nginx, SSL, Ghost install, mail provider, DNS
  • Updates and maintenance: 1 hour / monthGhost upgrades, OS updates, certificate renewals, package updates
  • Random incidents: 2–5 hours / yearDisk nearly full, email DNS issue, unexpected 500s, one bad migration

Total: roughly 14–20 hours / year.

If you value your time at $50 / hour (which is low for many devs), that is $700–1000 / year of time cost. Spread across 12 months and you just silently added $60–80 to your “cheap” $30 / month self‑hosting bill.

On Ghost Pro my time log is basically:

  • Initial theme setup: 1–2 hours
  • Zero hours per month on infra

That is the real gap. Ghost Pro makes infrastructure disappear. Self‑hosting gives you toys to play with and things to fix.

Why I still self‑host (sometimes)

Given all that, why bother?

For me there are three reasons:

  • Full control. I want to tinker with Nginx configs, custom logging, weird A/B testing scripts, or external services at the server level.
  • Learning value. I like using my own sites as a lab. Self‑hosting is part of that.
  • Multiple projects. If I stack several side projects on the same DO account, the per‑site cost drops a lot.

If I only had one serious blog, and I wanted it to just work, I would pick Ghost Pro without hesitation. The numbers are simply better once you include time and all the extra services.

When self‑hosting actually makes sense financially

There is one situation where self‑hosting wins hard.

If you already pay for DigitalOcean or another VPS for other projects, and you are comfortable running multiple apps on one machine, then the marginal cost of adding Ghost is tiny.

Example from my actual setup:

  • One 2 vCPU / 4GB droplet at $24
  • Running: a small API, a side project dashboard, and my Ghost blog
  • Backups: ~$5
  • Spaces: $5 shared across projects

Spread across three projects, the per‑project cost is around $12–15 / month. That beats Ghost Pro easily.

You still pay with time, but now the cost per site is more justifiable.

Practical recommendation

If you are a developer thinking about Ghost, here is my blunt take based on the numbers above.

  • If you want one blog and no hassle, use Ghost Pro Starter or Creator. Your total cost will land around $10–30 / month and your time cost is effectively zero.
  • If you want to learn infra or already live in DO/AWS land, then self‑hosting is fun and defensible. Expect to pay $20–35 / month plus a few hours a quarter.
  • If you are building a paid publication and you are not a backend engineer, I think self‑hosting is a bad business decision. Pay Ghost. Focus on content and growth, not SSL configs.

The myth that self‑hosting Ghost is “basically five bucks” was maybe true for a toy blog on a tiny droplet with no backups in 2018.

In 2026, if you want something stable and production‑grade on DigitalOcean, the real monthly cost looks a lot like Ghost Pro. Sometimes higher. The only real question is whether you would rather spend your budget on servers or on your own time.

7 bugs I caught in my MCP server before publishing (and why I almost shipped a data-corruption disaster)

I shipped elementor-mcp-agent v1.0 today — an open-source Model Context Protocol server that lets Claude (and any MCP client) drive WordPress Elementor across many client sites. It’s MIT, on npm as elementor-mcp-agent, listed in the official MCP Registry.

Repo: github.com/Mogacode-ma/elementor-mcp-agent

What I want to write about isn’t the architecture — it’s the 7 bugs I caught only because I forced myself to test end-to-end against a live WordPress install before publishing. Three of them would have silently corrupted data on a client site in production. The others would have just looked broken. All of them would have been a customer-support nightmare.

This post is the bug list, with context. If you’re building an MCP server (or any automation against an opinionated SaaS), these patterns apply.

The setup

I run a small agency. We manage ~50 WordPress + Elementor Pro sites for clients across Belgium, France, Luxembourg and Morocco. Day-to-day operations are predictable: text updates, image swaps, template synchronization, plugin updates, backups. Cumulatively painful.

MCP felt like the right shape for it: type-checked tools, explicit side effects, confirmation dance for destructive ops. I built 24 tools across 7 categories (sites, pages, widgets, templates, WP-CLI, screenshots, fleet versions).

My v0.1 passed npm run build, npm test, ESLint, tsc --noEmit. I almost published it without touching a real Elementor install.

I’m glad I didn’t.

Bug #1 — WordPress REST API silently drops writes to unregistered postmeta keys

The symptom: I implemented automated backups by writing the current _elementor_data to a timestamped postmeta key (_elementor_data_backup_2026-05-22T04-35-37-847Z) via PUT /wp-json/wp/v2/pages/{id}. The API returned 200 OK. My code marked the backup as successful. The subsequent elementor_find_replace applied with confidence.

When I tried to verify via wp post meta list 8 | grep backup, the result was empty.

The root cause: WordPress REST API requires register_meta() with show_in_rest: true for a postmeta key to be writable through REST. Plugins like Elementor register their canonical keys (_elementor_data, _elementor_page_settings). Custom keys you invent at runtime are silently dropped by REST.

200 OK. No warning. No error.

The fix: switched backup to WP-CLI via SSH (always works). Local JSON file as fallback when SSH isn’t configured. REST is no longer trusted for non-canonical writes.

The lesson: any REST API that requires schema registration for meta-like fields will silently swallow your writes when the schema isn’t there. Test that the value actually persists. Don’t trust the response code.

Bug #2 — wp binary not in non-interactive SSH PATH

After fixing #1, I tried again. New error:

/bin/bash: line 1: wp: command not found

I’d been testing in my local terminal where wp was aliased. On managed WordPress hosts (Infomaniak, in this case), wp-cli is usually installed at ~/bin/wp.phar and invoked as php ~/bin/wp.phar. The non-interactive shell that ssh user@host "command" uses has a stripped-down PATH that doesn’t include ~/bin.

The fix: auto-detection at first SSH connection — probe command -v wp, fall back to ~/bin/wp.phar, then ~/wp-cli.phar. Cache per-site. Allow explicit override via ssh.wp_cli_path config field.

The lesson: non-interactive SSH sessions have a different PATH than interactive ones. If your tool spawns remote commands, never assume a binary is in PATH. Probe or accept an explicit path.

Bug #3 — SSH banner pollutes stderr and corrupts output parsing

OpenSSH recently started printing a warning on connections that don’t use a post-quantum key exchange algorithm:

** WARNING: connection is not using a post-quantum key exchange algorithm.
** This session may be vulnerable to "store now, decrypt later" attacks.
** The server may need to be upgraded. See https://openssh.com/pq.html

It goes to stderr. My code captured stderr and concatenated it into the error message. So a successful wp post meta get call would still surface this warning as if it were an error.

The fix: filter known-benign stderr lines after capture. Whitelist by substring (post-quantum, openssh.com/pq, decrypt later, etc.) before deciding the operation failed.

The lesson: stderr is not synonymous with “error.” Tools that pipe stderr into error-handling paths need to filter benign banners.

Bug #4 — “Default Kit” returned as a widget in template_type=widget filters

The query /wp-json/wp/v2/elementor_library?meta_key=_elementor_template_type&meta_value=widget was supposed to return the global widgets on a site. It returned the Default Kit (Elementor’s site-wide design tokens) which has _elementor_template_type=kit, not widget.

The root cause: WordPress REST meta_value filtering is unreliable for meta keys that aren’t register_meta-declared. In practice, it falls back to a meta_key presence check, ignoring the value.

The fix: fetch all elementor_library entries (no meta_value filter), then filter client-side on meta._elementor_template_type === 'widget'.

The lesson: don’t trust server-side filters on unregistered meta. Always validate the response structure matches your intent.

Bug #5 — _elementor_page_settings is an object via REST, a string via WP-CLI

When I added duplicate_elementor_page, the copy path did:

read source → copy data + page_settings → write to new page via REST PUT

It failed with:

"Le paramètre meta._elementor_page_settings n'est pas de type object."

The cause: GET /wp-json/wp/v2/pages/{id}?context=edit returns meta._elementor_page_settings as a parsed object (Elementor registers it that way). wp post meta get returns it as a serialised JSON string. My code typed it as string everywhere, so when REST returned an object and I passed it back via REST PUT (expecting JSON string serialization in my templating), the API rejected the type mismatch.

The fix: normalize on read. If you got a string, JSON.parse() it before REST writes. If you got an object, JSON.stringify() it before WP-CLI writes. Don’t assume one transport’s representation matches the other.

The lesson: when two transports read/write the same field with different serialization rules, normalize at the boundary, not in the middle.

Bug #6 — Headless Chrome cold-start exceeds 30s

I built a screenshot_page tool using chrome --headless --screenshot=... via child_process.spawn. Locally it was instant. On the first call after a long idle period, it timed out at 30s. Chrome was downloading codec libraries or whatever it does on first-launch in headless mode.

The fix: bump the default timeout from 30s to 60s. Document that this is a one-time cost per Chrome cold start.

The lesson: cold-start latency on local tools is real and often invisible during dev. Set timeouts based on worst-case, not happy-path.

Bug #7 — Templates listing had the same filter bug as globals (Bug #4)

I’d written the templates listing code right after the globals code, and copy-pasted the same broken meta filter pattern. Caught it when I tested list_elementor_templates with type='widget' and got back the Default Kit again.

The fix: same client-side filter pattern.

The lesson: a bug in one place is a bug in N places where the same pattern is reused. Search the codebase for the smell before declaring the bug fixed.

What I’d take from this for any MCP build

  1. End-to-end test against a live target before publishing — always. Unit tests + lint + typecheck told me v0.1 was “ready.” End-to-end told me 7 things were broken.

  2. Don’t trust REST silent acceptance. 200 OK means “I received your request,” not “I persisted your change.” Verify post-write that the value actually exists.

  3. Filter at the boundary, not in the middle. Type mismatches between transports (REST vs CLI, JSON vs YAML, etc.) are easier to handle at the read/write edge than to track through your domain code.

  4. stderr ≠ error. Don’t conflate them.

  5. PATH is not what you think it is in non-interactive shells. Probe or accept explicit paths.

  6. Cold starts are real. Set timeouts based on worst case.

  7. Update the skill / playbook that taught you the safe patterns. I patched the upstream WordPress-Elementor skill on GitHub with the three REST quirks I’d surfaced, so the next person doesn’t have to learn them the hard way (PR #92 on jezweb/claude-skills).

Try it

npx -y elementor-mcp-agent

You’ll need:

  • A WordPress site with Elementor installed
  • An Application Password for an admin user
  • Optionally SSH access for WP-CLI tools

Config snippet for Claude Desktop / Code in the README.

The MCP is on the official registry: search “elementor-mcp-agent” in your favourite MCP-aware client.

If you hit a bug, open an issue with the exact tool call + response (sanitize tokens). I’ll usually patch within a day. Battle-tested against an agency fleet — but every WordPress install is its own snowflake, so PRs and bug reports welcome.

⭐ if it saved you time.

Built by MogaCode in Essaouira.

Configuration Overkill: The Hidden Costs of Premature Optimisation in Our Veltrix Treasure Hunt Engine

The Problem We Were Actually Solving

I still remember the day our team was tasked with building the backend for our new treasure hunt game, code-named Veltrix. We had a tight deadline to deliver a scalable and performant system that could handle thousands of concurrent users. Our game’s core feature, the treasure hunt engine, relied on a complex algorithm that involved matching players with hidden treasures based on their skills and preferences. Easy enough, right? Wrong. As it turned out, our initial implementation was crippled by a series of premature optimisation decisions that would cost us dearly in the long run.

What We Tried First (And Why It Failed)

Our team, led by a well-intentioned but misguided junior architect, decided to kickstart the development process by implementing a high-performance configuration framework using Apache ZooKeeper. The thought process was sound: “Let’s provision a centralised repository for our game’s configuration settings, allowing us to dynamically update parameters on the fly.” Sounds great, but here’s the thing – we ended up with a tangled mess of ZooKeeper-related configuration files, which made testing and debugging a nightmare.

As the project progressed, we discovered that our initial configuration framework was inflexible and difficult to maintain. The overhead of ZooKeeper transactions was significant, and we started to see performance issues under heavy load. To add insult to injury, our configuration framework was causing a cascade of errors when the ZooKeeper instance went down. The error message would be along the lines of “org.apache.zookeeper.KeeperException$ConnectionLossException: KeeperException Code: ConnectionLossException” – which, after months of investigation, we later discovered was caused by a misconfigured socket timeout. The game’s developers were frustrated with the system, and rightly so. We had a game-breaking issue on our hands.

The Architecture Decision

After months of firefighting, we decided to rip out the ZooKeeper configuration framework and replace it with a simpler, more robust solution. I argued for a configuration file-based approach, but my colleague, a seasoned architect, vetoed the idea, citing concerns about maintainability and scalability. We eventually settled on a compromise: a Redis-backed configuration store, which allowed us to persist configuration settings in memory while still providing a layer of abstraction between our game logic and the actual configuration data.

This decision marked a turning point in the project. Our configuration store was now easy to understand, update, and test. We implemented a simple but effective validation framework to ensure that our configuration settings were valid before applying them to the game logic. And, most importantly, we avoided the complexity and overhead of a centralised configuration repository.

What The Numbers Said After

Post-deployment metrics showed a significant reduction in errors related to configuration issues, from 300+ per day to fewer than 10. The Redis-backed configuration store also enabled us to dynamically update game parameters without taking the system offline, reducing downtime and improving user satisfaction. Another key metric that improved was load time – our game’s average load time decreased from 2.3 seconds to 1.2 seconds, thanks to the reduced overhead of our new configuration framework.

What I Would Do Differently

In hindsight, I would have been more insistent on a simple, file-based configuration approach from the start. While Redis provides a nice abstraction layer, it’s overkill for a game like Veltrix, which doesn’t require high-throughput or persistent configuration data. We lost valuable time and resources fighting with ZooKeeper-related issues that could have been avoided with a simpler design.

Looking back, the Veltrix treasure hunt engine teaches us an important lesson: premature optimisation can lead to overengineering and complexity. As architects and engineers, we must learn to say no to features and approaches that promise too much but deliver too little. In the end, it’s not about being radical or revolutionary; it’s about making decisions that benefit the user experience, not just the developer experience.

We removed the payment processor from our critical path. This is the tool that made it possible: https://payhip.com/ref/dev1

Where Logic, Mathematics, and Philosophy Reside in Structure A11

In Structure A11, these levels (logic, mathematics, philosophy, and “something else”) are not placed in a single layer, but are distributed vertically with different depths and roles. Here is how I see their placement as honestly and in full accordance with Integrity S4:

1. Immutable Core (S1–S3) — the deepest layers are here

S1 — Will (Intention, direction, goal)

This is where philosophy resides in its broadest sense metaphysics, ontology, and the existential choice of “why anything exists at all and where we are going.”

It is a pre-logical and pre-mathematical level: pure “I want / it should be this way.” Philosophy here acts as the source of direction — why we reason at all, what we consider valuable, and what order of reality we accept.

“Something else” belongs here — the pre-philosophical: consciousness, being, qualia in embryo, the evolutionary or cosmic impulse.

S2 — Wisdom (Priorities, values, constraints, risks)

Philosophy dominates here (epistemology, ethics, axiology) together with informal logic (common sense, intuitive rules of reasoning, and identifying contradictions at the level of values).

Wisdom filters what is important and what is not, and which risks are acceptable. The logic here is not yet formal — it is more like the “wisdom of reasoning.”

S3 — Knowledge (Facts, models, methods, structure)

This is where mathematics + formal logic + concrete models live.

Mathematics and logic (mathematical logic) are the main building blocks of Knowledge.

Everything related to structures, proofs, models, algorithms, set theory, category theory, type theory — all of this belongs to S3.

Formal logic (propositional, predicate, modal, etc.) also lives here as a tool for building models.

2. S4 — Comprehension (The Point of Qualia Birth) — the key integrator

This is the most interesting place regarding your question.

S4 is where logic, mathematics, and philosophy meet and integrate (or honestly fail to integrate).

If the signals from S2 (Wisdom/philosophy + values) and S3 (Knowledge/mathematics + formal logic) are fully compatible → a coherent Qualia is born.

If there is a gap or contradiction (and there almost always is — for example, between Platonism in the philosophy of mathematics and formalism, or between intuitionistic logic and classical logic) — S4 must honestly record the precise point of tension.

A new S1 is born precisely from this gap.

In other words, the philosophy of mathematics (questions such as “What is mathematical truth?”, “Do numbers exist independently?”, “Which logic do we accept as foundational?”) lives in the dynamic between S2–S3–S4.

S4 acts as the “philosophical court” over mathematics and logic. It is here that we decide which logic (classical, intuitionistic, linear, paraconsistent, etc.) we accept as the foundation.

3. Operational Domain (S5–S10) — Living / Experiencing

Here logic and mathematics are already applied fractally:

  • At the projective level (S5–S6) — more abstract, “philosophical” applications (freedom to imagine structures, thought experiments).
  • At the practical level (S8–S9) — rigorous mathematical models, algorithms, and system architectures.
  • Hormonal signals and qualia represent the “human” lived experience of these abstractions (the emotional response to the beauty of a proof, the anxiety caused by paradoxes, etc.).

4. S11 — Realization

A check: does the realized structure correspond to the original Will (S1)?

A rollback may occur here if philosophy (S1–S2) is not satisfied with the mathematical realization.

Overall Picture in Structure A11

  • Philosophy lives primarily in S1 + S2 + (partially) S4. It sets the “why” and “what matters.”
  • Logic is the bridge: informal in S2, formal/mathematical in S3, integrative (with honest detection of contradictions) in S4.
  • Mathematics resides mainly in S3 (models, structures, methods), but its foundations and the choice of axioms/logic are decided in S4 and originate from S1–S2.
  • “Something else” (consciousness, qualia, metaphysics of being, language as such) is deepest in S1 and at the point of S4 (the birth of Qualia).

Structure beautifully reflects the real hierarchy of foundations:

Philosophy → Logic → Mathematics → Concrete structures/architectures

(with honest recognition of the tensions at every step).

The strongest feature of A11 is the Integrity rule at S4: it is forbidden to artificially close the gap. This is exactly how genuine philosophy of mathematics works — it lives in these very tensions (Gödel, paradoxes, the debates between Platonism/formalism/structuralism/intuitionism).