# AI Should Stop Generating the Same Code Over and Over

> Source: <https://dev.to/cordango/ai-should-stop-generating-the-same-code-over-and-over-fe5>
> Published: 2026-09-11 21:55:33+00:00

AI coding tools have become ridiculously good...guess we can all agree. 

You can describe an application, wait a few minutes, and suddenly you have React components, API endpoints, database models, authentication, migrations and a decent-looking application...it seems to be magically. Then you dig into the code, try to change something and something you didn't even remotely touch breaks. Then you spend another few thousand tokens explaining the architecture the AI itself created 30 minutes ago.

I was sick of it....

As part of a platform for small businesses I'm currently working on I am also experimenting with a different architecture for AI-built business software: let AI describe the application, then compile the repeatable parts deterministically especially do not have the AI build things like authentication, connectivity, database stuff...you name it. That has all been solved for 20 years and we shouldn't ask AI to build it over and over again, failing over and over again at getting things right.

The AI only has to write YAML using my own vocabulary. 

Think about something like this:

```
entity: expense_claim

fields:
  submitted_by:
    type: reference
    targetEntity: person

  amount:
    type: money
    currency: EUR
    required: true
```

or this..a little bit more involved:

```
entity: assumption
ownedBy:
  parent: scenario
  via: scenario
  as: table
display: statement
fields:
  statement:
    label: Assumption
    type: text
    required: true
  scenario:
    label: Scenario
    type: reference
    required: true
    indexed: true
    targetEntity: scenario
    onDelete: cascade
```

And this isn't limited to entities or CRUD.

Automations can be described in the same vocabulary:

```
automation: build_segment_grid
name: Lay out a segment's lifecycle
effects:
  - type: createForEach
    set:
      scenario: '{{record.scenario}}'
      segment: '{{record.id}}'
      point: '{{source.id}}'
      label: '{{record.name}} {{source.label}}'
      flex:
        pick:
          entity: revenue_plan
          filters:
            - field: scenario
              operator: eq
              value: '{{record.scenario}}'
            - field: tier
              operator: eq
              value: flex
          sort:
            - field: name
              direction: asc
```

We can describe the whole application with YAML definitions, from entities, relations, workflows, automations, permissions up to views and screens and readymade widgets...its all in YAML.

Yet, The exact YAML isn't really the important part.

It could be JSON. It could eventually be authored visually. Most of the time it may simply be written and modified by an AI.

The definition says what the business application should do. It doesn't describe how ASP.NET should register a controller, how EF Core should configure a relationship, how Vue should render the form or how an MCP tool should expose the operation, and ASP.NET is just an example here I use as thats the first target compiler that exists today. More to come.

Yet...those things can be derived.

And hey, YAML rings a bell. Someone must have built something like this before. Absolutely!

Lowdefy, for example, takes a similar approach in some ways: you describe an application using YAML instead of manually writing all the implementation code.

But there is one important architectural difference.

Lowdefy's YAML describes an application for the Lowdefy runtime. The runtime interprets that configuration and provides the UI, data connections, actions, authentication and other application machinery.

That is a perfectly valid architecture, but your application is fundamentally expressed in terms of that runtime.

My approach is different and goes way beyond that!

For my project theres two options...The first is to run the application on the Cordango platform. The definition is compiled into an internal JSON representation which the platform uses to build and run the app.

The platform adds some nice things on top, like apps sharing company data and reacting to each other's events without somebody having to manually build an integration between every single tool. But that's not really what I want to talk about here.

The second path is the more interesting one for this article:

Not a starter template. Not a few generated models you still have to wire together. An actual standalone application with a frontend, backend, database model, migrations, authentication, permissions, business logic, REST/OpenAPI and MCP.

Something you can take, build, run and host yourself.

The current architecture looks roughly like this:

```
                App Definition
                     |
                     v
            Deterministic Compiler
                     |
          +----------+----------+
          |                     |
          v                     v
       Frontend               Backend
      Vue / Vuetify        ASP.NET Core
          |                     |
          |          +----------+----------+
          |          |          |          |
          |       REST/API     MCP      Commands
          |       OpenAPI                Workflows
          |                     |       Permissions
          |                     |       Calculations
          |                     |
          +----------+----------+
                     |
                  EF Core
                     |
              Database Model
                 Migrations
                     |
                 PostgreSQL
```

Today the first complete target generates ASP.NET Core + EF Core + PostgreSQL + Vue 3/Vuetify but Node/Typescript is on its way, Python is being planned and more to come.

And because all of those pieces come from the same application definition, they don't have to be separately invented and kept in sync.

If the definition says an expense_claim exists, that isn't just a database table.

The compiler can derive:

the entity model

persistence

migrations

CRUD operations

permissions

forms and views

REST/OpenAPI

MCP access

commands and workflows

Change the definition and the generated implementation changes with it.

The YAML isn't configuration for the generated application. It is the source from which the application is compiled.

And this leads to one of my favorite slightly ridiculous consequences:

I'm serious.

If your App Definition is stored in Git and you pin the compiler/generator versions required to build it, the generated source becomes a build artifact.

Given the same application definition, generator version and scaffold version, the compiler generates the same files again.

So technically your repository could look roughly like this:

my-app/

├── cordango.yaml

├── apps/

│   └── expenses/

│       ├── app.cordango.yaml

│       ├── entities/

│       ├── roles/

│       ├── views/

│       └── workflows/

└── .gitignore

while this:

generated/

├── api/

├── web/

├── Dockerfile

└── docker-compose.yml

could simply be regenerated whenever you need it.

Now, whether you should gitignore all generated source is a different discussion. Keeping generated code in Git can obviously be useful for reviewing changes, deployments and debugging.

But architecturally, you don't have to treat it as the source of truth anymore.

That's the important part.

The definition is the source. The code is an output.

And unlike a traditional runtime-based no-code platform, taking that output doesn't mean taking a dependency on my hosted service.

There is no Cordango account requirement, licence server, model API or phone-home service involved in running the generated application.

The current standalone runtime is small enough that it can either be referenced as a package or embedded into the generated project itself.

So you can generate the application, take the source, and host it wherever you want.

With this approach, the AI gets more headroom to reason about the actual business problem instead of spending context and tokens on code we've already solved a thousand times.

It also has far less room to accidentally break unrelated implementation details. If it changes a workflow, it changes the workflow definition. The compiler handles the rest.

The AI can still misunderstand the requirement, of course. But those are business-level mistakes, not random implementation drift.

And it doesn't even have to be a coding model...I literarily build one of the sample apps with ChatGPT...yes the old standard one, not codex.

I don't want to make this the main part but yes, using YAML saved a ton of token. I compared the generated examples vs the YAML definition with Anthropic's tokenizer and the result was up to 98% fewer token consumed...lets see how that adds up when more work is done but it definitely saves you..some huge chunk.

YAML alone doesn't solve much if the AI still has to read an entire repository every time something changes. So Cordango comes with a CLI around the application model.

The basic loop becomes:

```
Describe a change
      ↓
AI changes the relevant definition
      ↓
cordango check
      ↓
cordango build
      ↓
Deterministically generated application
```

The AI works on the small semantic representation, not hundreds of generated controllers, migrations, components and API files, the CLi gives the AI the tools it needs to do that. And because the compiler understands the vocabulary, it can reject invalid definitions before they ever turn into source code.

cordango check

cordango build --target app --generator dotnet-vue

That's really the whole bet.

Want to have a look?

[https://www.github.com/cordango](https://www.github.com/cordango)

[https://docs.cordango.com](https://docs.cordango.com)

[https://www.cordango.com](https://www.cordango.com)

All feedback welcome, negative, positive, roast it, praise it...give it a try!

make the thing AI has to understand smaller, more meaningful and harder to accidentally break.
