MWFAI Middleware Factory / Artificial Intelligence

Business Systems

Your agents should work on your business, not on a copy of it.

One model. Human screens derived from it. Agent tools that write into it — through the same constraints, inside the same transactions, under the same permission check.

The problem, without caricature

The usual architecture has two halves that never quite meet. On one side, a database, a backend, an API and a front end. On the other, documents, embeddings and an agent that reads about the business without ever touching it.

The second half is safe because it is powerless. The moment you let it write, you discover that your business rules live in the first half — in forms, in controllers, in the screens themselves.

What we build

We build the business model first, as a graph where types, instances, attributes and relations share one formalism. From there:

The screens are derived from the model. Not generated once and then maintained by hand — derived, so a change to the model reaches the interface.

Agents call tools against the same model. They discover the schema, resolve canonical references, traverse relations, and write inside transactions.

They can rehearse before they commit. A mutation can be run as a dry run: the agent sees exactly what would happen, and nothing happens.

Constraints belong to the model, not to the form. Cardinality, uniqueness, required values and referential rules are enforced where the write lands, so they hold for a human, an agent, an import or a scheduled job alike.

The refusal

One invoice — FACT-2026-000002, a draft — and one user: a manager whose role creates and edits invoices but cannot delete them. The delete, from two sides: the manager's own screen, and an agent badged as the same manager. This is gs-invoice on live data. Nothing here is a test.

The manager's invoice list in gs-invoice: six invoices, no delete control on any row, not even on the draft
The human. Logged in as the manager. The delete action is not offered: no control on any row, not even on the draft. A right that is missing is a gesture that does not exist.
authenticate
  { "login": "gestionnaire", "password": "••••••••" }
→ { "login": "gestionnaire", "principal": "gestionnaire", "badged": true }

remove_instance_by_ts
  { "instanceTs": "1787312345772497468", "dryRun": true }
→ Write refused: the principal gestionnaire may not DELETE
  class org.genericsystem.invoice.model.Organisation$FacturesEmises.
The agent. Badged as the same manager through its authenticate tool, it calls remove_instance_by_ts on the same invoice, as a dry run. The refusal is the rights check at the write boundary — it fires before the write, dry run or not.

One permission, enforced at the write boundary — the deletion refused whether the gesture comes from a human (an action not offered) or from an agent (an attempt refused). The invoice is still there.

The proof

gs-invoice is a production invoicing application on this architecture — organisations, clients, products, taxes, invoices, lines, payments, issuance, PDF, credit notes, users, roles, and data separated per organisation. Its scope is real and bounded: bank reconciliation, accounting-software export, reminders, recurring billing and multi-currency are out of scope, as the Why now case states.

gs-postal and gs-importer show the entry path most companies actually need: an existing operational dataset — spreadsheets, exports, a legacy extract — becomes a structured model that people and agents can both operate, with the ETL sharing the very same model as the application.

How it starts

We start as a project, not as a platform sale. A first system, scoped to something you can put in production, with your data and your rules. You are reserving a production capacity against a measured objective — defined and tracked, not guaranteed; the generalisation follows from real use, not ahead of it.

Bring a process you would never let an agent near.

That is the one worth walking through together.