What I'm Building
My goal is to be an enabler for small businesses. In the past, many small businesses could not afford custom software to automate their work. I want to make custom business software dramatically faster and more affordable by moving workflow, UI binding, forms, logging, database access, and platform behavior into a declarative, testable framework. I plan to add a powerful database pane and a workflow pane so I can build useful business applications quickly enough that small businesses can afford them. The database layer will support defining tables, generating data-entry screens, and providing list views with filtering and sorting automatically. Security should be managed in the database and framework boundaries, not scattered through application code.
I am building a tool to make tools: a Python coding platform and application framework built around a strict seven-layer architecture, implemented in nine directories:
- l1_ui: Passive widgets and screens that display state and emit user signals. A “dumb” UI with no business logic.
- l2_bridge: Transport adapters, one per platform: Qt on the desktop, QML on Android, and FastAPI with HTMX on the web.
- l2_facade: A thin, stateless entry point into the runtime. It holds no state of its own.
- l2_runtime: The platform-neutral runtime. It carries signals between the UI and the state machine, sequences them, and manages sessions. It owns no workflow.
- l3_fsm: Declarative hierarchical state-machine authority for workflow, events, transitions, and orchestration.
- l4_muscle: Atomic actions and pure guards invoked by the state machine, plus the compile-time checks that block a release when a workflow fails them.
- l5_dal: Curated data-access layer for app-owned database reads and writes.
- l6_infra: Framework/system infrastructure boundaries such as logging, files, auth, network, and platform APIs.
- l7_model: Frozen typed vessels and semantic data shapes that cross layer boundaries.
Dependencies flow downward. Upper layers may import lower layers, but lower layers may not import upward. A strong linter enforces these architectural rules.
Layer 3 is a Hierarchical State Machine engine. Application orchestration is done with State Machines, not imperative control flow scattered through code. State Machines are used in safety-critical systems such as cars, airplanes, spacecraft, nuclear power plants, medical equipment, industrial controls, and ordinary appliances. They are common in hardware and embedded systems, but much less common in the business and end-user applications most programmers build today. I believe they have strong advantages for those “regular” applications too. That is what I am aiming for.
The template application currently contains a State Machine Map Viewer pane and a Logging pane. More panes may be added to the base template later after they are developed as applications themselves.
This is an application development framework. I can make a new application from the template, add my own State Machine Maps and panes, and create any kind of application I need. This is how tools are made with this tool.
Because the architecture has strong separation of concerns, one application can target a desktop, a phone, or a browser by changing only the top two layers: the widget layer and the bridge layer. There is an adapter for each target, using Qt on the desktop, QML on Android, and FastAPI with HTMX on the web. Everything beneath them is shared: the workflow map, the actions, data access, infrastructure, and the typed data models. Testing the State Map benefits every platform at once. The workflow is written once and only the presentation is adapted.
State Machine Maps are declared in a database. That is a very effective way to model them because states, events, transitions, guards, actions, UI bindings, forms, and runtime metadata can all be stored as structured relational data. The maps are exported into signed JSON contracts that the runtime consumes. I use AI to help create the State Machine Maps and the supporting code. It is a great time to be alive.
The platform has a separate state machine for an ESP32-S3 microcontroller. I have a smart watch running an application on the compact state machine runtime written for the microcontroller. It is driven by a contract generated from the same state machine database system that produces the desktop, Android, and web applications. It is a separate implementation rather than a port but it uses the same map making and viewing mechanism that the big applications use.
Here are some useful features you get automatically by making an application in this State Machine driven environment.
Menus and Buttons
In imperative code, converting button and menu clicks into actions and managing enablement is tedious. In this framework, a row in the State Machine database says, “This button or menu item emits this Event.”
When the user clicks the button or menu item, the bridge layer uses the mapping to emit the declared Event into the State Machine engine automatically.
That Event is only legal in certain States, as defined by the State Machine Map. The framework uses Event Legality to enable or disable the button or menu item automatically. If the Event is legal from the current State, the control is enabled. If the Event is not legal from the current State, the control is disabled. It’s very elegant.
The UI does not decide this with custom code.
Forms and Dialogs
Forms and dialogs are bound to States in the State Machine map. When a bound State is entered, the form or dialog is shown. When that State is exited, it is hidden. One line in a database table sets this up.
A form declaration includes the container widget, fields, submit signal, cancel signal, payload bindings, validation rules, dirty tracking rules, and reset/retain lifecycle policy.
The transport layer uses that metadata to:
- show or hide the form with its owning State or dialog;
- sample field values into the declared payload;
- route submit and cancel signals to State Machine Events;
- enable submit only when the Event is legal, required fields are valid, and dirty rules are satisfied;
- reset or retain form values according to the declared close policy.
The form is described in the database. Runtime projection, validation, dirty tracking, reset, payload creation, and event routing are handled by the framework. The UI remains passive. The State Map owns the workflow.
Form fields are declared in the database too. A field declaration includes which form the field belongs to, which widget supplies the value, which payload key or target variable it maps to, the expected target type, whether it is required, whether visibility is projected by the framework, and how it participates in reset/retain lifecycle.
Those rows are exported into the compiled JSON contracts. At runtime, the framework reads the contract, finds the widgets, samples the declared properties, validates required fields, builds the payload, and routes submit and cancel Events into the State Machine.
I am moving toward a comprehensive model where more and more application behavior is defined as metadata in the database and executed by the framework.
Typical Form Submission Flow
- The user submits the form.
- The declared submit signal emits an Event into the State Machine.
- The transport layer samples the declared fields and builds the payload.
- The State Machine checks whether the Event is legal in the current State.
- Declared payload keys are copied into typed workflow variables.
- Optional declared transforms normalize, combine, split, or reshape the data without custom Python.
- A curated data-access method is called with declared typed inputs.
- The data layer performs the actual database read or write through the framework boundary.
The UI emits intent. The State Machine orchestrates. Declared bindings and transforms prepare typed data. The data layer performs persistence through the proper boundary.
Current Status
I am using this framework to build real applications so I can shake out the bugs and improve the platform.
Currently I have:
- a Personal Knowledge Management system running on both desktop and Android with a PostGreSQL database to sync with.
- a rapid application development database application in progress. This will become meta-data driven and very fast to make database applications with.
- an ESP32-S3 smart watch running its own application on the embedded build of the engine. It records voice notes, uploads them to my server where an AI transcribes them and then they show up in the Inbox of the Personal Knowledge Management system.
- additional generated applications used to test and harden the framework. Email, Calendar, Contacts, AI Client.