Omega
Architecture
The autonomous nervous system for high‑complexity Flutter applications.
This site is the complete documentation for Omega. It includes: data flow step by step, a glossary of terms, everything the framework offers, examples by use case, core concepts, comparison with BLoC and Riverpod, diagram, installation, CLI, integration, flow lifecycle, API reference for each class, persistence, inspector and testing. For more examples in the repo see doc/GUIA.md and the example/ app. Production app built with Omega: Kashira (full working architecture).
What’s new in Omega
Quick summary of recent improvements to the framework and tools.
For full details see CHANGELOG.md in the repository.
0.0.26 — CLI Robustness & UX
Enhances developer experience with a smarter CLI that automates route wiring and initial setup without errors.
- Automatic Route Registration: When generating a module (ecosystem), the CLI now automatically registers the route and adds the UI import in
omega_setup.dart. - Fixed Smoke Tests:
test/widget_test.dartgeneration is now fully compatible with Omega, removing residualMyAppdependencies. - Quick Start: New section in the documentation for activating and creating apps in seconds, including AI environment variable configuration.
- Windows Robustness: Improved path resolution and forced overwriting to ensure a clean initial setup.
Key command:
# Activate the updated CLI locally
dart pub global activate --source path .
0.0.25 — Orchestration & App Creation
Introducing omega create app, an orchestrator that automates the full setup of an Omega project from scratch, including intelligent AI assistance.
- App Creator:
omega create app <Name>coordinatesflutter create, dependencies, andomega initin a single step. - AI Kickstart: The
--kickstartflag allows the AI to write real business logic (agents, flows, and UI) based on your description, moving beyond generic templates. - Standard Navigation:
OmegaNavigatornow supportsonGenerateRoute, enabling the use ofNavigator.pushNamedwith Omega routes. - Automatic Smoke Tests: The generator cleans up default Flutter tests to ensure the new project compiles and passes tests out of the box.
Example:
# Create a crypto app with real logic generated by AI
omega create app omega_crypto --kickstart "real-time crypto dashboard" --provider-api
0.0.23 — AI Evolution & Advanced Generation
Supercharge your development workflow with AI-assisted commands to diagnose, audit, and generate full modules following Omega's best practices.
- omega ai coach module: Generates full ecosystems (WorkflowFlow, StatefulAgent, Typed Events, Contracts, and Tests) with a single command.
- Feature Auditing:
ai coach auditanalyzes your real project, detecting wiring (setup) gaps, missing contracts, or tests for a feature. - Editor Reports: AI commands now default to opening a temporary Markdown report in your editor for better readability, with a
--stdoutoption. - Plug-and-Play UI Templates: Generated UI pages now dynamically connect to
FlowManagerviaOmegaScopewithout manually passing the agent.
Command Example:
# Generate a full module with assisted advanced architecture
dart run omega_architecture:omega ai coach module "Payment" --template advanced
0.0.22 — Reactive agents and workflow flow
This release adds two optional capabilities to scale UI/processes without compromising the core:
OmegaStatefulAgent + OmegaAgentBuilder, and
OmegaWorkflowFlow.
- Reactive agent state:
OmegaStatefulAgent<TState>exposesviewState/stateStreamso UI can react to agent state without duplicating logic. - UI helper:
OmegaAgentBuilderlistens to agent state and rebuilds widgets (loading/error/view state) declaratively. - Optional workflow engine:
OmegaWorkflowFlowmodels step-based processes withdefineStep,startAt,next,failStep, andcompleteWorkflow.
Example:
class AuthAgent extends OmegaStatefulAgent<AuthViewState> {
AuthAgent(OmegaEventBus channel) : super(
id: "Auth",
channel: channel,
behavior: AuthBehavior(),
initialState: AuthViewState.empty,
);
}
OmegaAgentBuilder<AuthAgent, AuthViewState>(
agent: authAgent,
builder: (context, state) => state.isLoading
? const CircularProgressIndicator()
: const SizedBox.shrink(),
);
0.0.21 — Typed events
Introduces OmegaTypedEvent and emitTyped so your events can be
classes with name + data instead of plain strings with loose payloads.
- OmegaTypedEvent + emitTyped: define event classes
(for example
LoginRequestedEvent) and emit them withchannel.emitTyped(...); listeners read them withevent.payloadAs<LoginRequestedEvent>(). - Updated example: the auth flow in the example app uses typed events to showcase the recommended pattern.
- Docs aligned:
README.mdanddoc/GUIA.mdnow present typed events as the preferred style, reducing magic strings and runtime bugs.
Example:
// Define the typed event
class LoginRequestedEvent implements OmegaTypedEvent {
LoginRequestedEvent(this.email, this.password);
final String email;
final String password;
@override
String get name => AppEvent.authLoginRequest.name;
}
// Emit from the flow
channel.emitTyped(LoginRequestedEvent(email, password));
// Read in the agent
final ev = event.payloadAs<LoginRequestedEvent>();
if (ev != null) {
// use ev.email, ev.password
}
Quick Start
Activate Omega globally and create your first project in seconds.
1. Global Activation
Install the Omega CLI on your system to use it from any folder:
dart pub global activate omega_architecture
Note: Ensure Dart's PATH is configured if the command is not recognized.
2. Create your App
Use the create app command to generate a pre-configured project:
omega create app my_app
This creates the project, adds dependencies, and initializes Omega.
Want to go faster? Use the AI kickstart to generate initial business logic:
omega create app my_app --kickstart "an e-commerce" --provider-api
Getting started with Omega
Installation, first use and running the example in three steps.
1. Add the dependency
In your app’s pubspec.yaml:
dependencies:
omega_architecture: ^0.0.26
2. Initialize in your app
From the project root:
dart run omega_architecture:omega init
This creates lib/omega/omega_setup.dart. Then
register agents, flows and routes inside createOmegaConfig.
3. Generate an ecosystem (optional):
dart run omega_architecture:omega g ecosystem Auth generates agent, flow,
behavior and page in the current directory and registers them in omega_setup.dart.
Run the example:
cd example && flutter run. It includes login, navigation with typed payload and
usage of OmegaRoute.typed<T> and payloadAs<T>.
Data flow in Omega
In Omega the UI does not call business methods; it emits intents. The channel, flows and agents do the work; the UI only reflects the result.
Step 1 — The UI emits an intent
The user taps “Sign in”. The screen does not call AuthService.login();
it calls
flowManager.handleIntent(OmegaIntent.fromName(AppIntent.authLogin, payload: creds)).
The intent carries the semantic name ("auth.login") and the data (credentials).
Step 2 — The flow (running) receives the intent
OmegaFlowManager sends the intent only to flows that are in
running state. AuthFlow receives it in onIntent(ctx). There it can: emit a “loading” expression for the UI, and emit an event on the channel to ask the
agent to work:
channel.emit(OmegaEvent.fromName(AppEvent.authLoginRequest, payload: ctx.intent!.payload)).
Step 3 — The agent reacts and emits events
The agent is subscribed to the channel. Its behavior engine evaluates the
context (event "auth.login.request") and returns a reaction, for example "doLogin" with the
payload. The agent executes onAction("doLogin", payload): it calls the API,
validates and emits emit("auth.login.success", payload: user) or
emit("auth.login.error", payload: error).
Step 4 — The flow reacts to the event and updates UI / navigation
The flow listens to the channel. When "auth.login.success" arrives, in onEvent(ctx)
it emits an expression toward the UI
(emitExpression("success", payload: ctx.event!.payload)) and, if appropriate, a
navigation intent:
channel.emit(OmegaEvent(..., name: "navigation.intent", payload: OmegaIntent.fromName(AppIntent.navigateHome, payload: userData))).
Step 5 — The UI and the navigator react
The screen is listening to flow.expressions; when it receives "success" it
calls setState and shows the result. OmegaNavigator (wired to the
channel with wireNavigator) receives the "navigation.intent" event, extracts the intent
and performs pushReplacement to the "home" route, passing the payload as arguments. The
home screen receives the data already typed if you use
OmegaRoute.typed<LoginSuccessPayload>.
Glossary: key definitions
Terms you will use across the whole Omega ecosystem.
| Term | Definition |
|---|---|
| Event (OmegaEvent) | Representation of “something that happened” in the system. It has a
name (e.g. "auth.login.success") and optional
payload. It is published on the channel and received by all
subscribers (agents, flows, OmegaBuilder). |
| Intent (OmegaIntent) | Business‑level request: “I want to log in”, “I want to go home”. The UI emits
intents; it does not call methods. OmegaFlowManager routes them to
flows in running state. They are also used for navigation; the payload
reaches the screen as route arguments. |
| Expression (OmegaFlowExpression) | Message that a flow sends to the UI: “loading”, “success”, “error” (with type and
payload). The UI subscribes to flow.expressions and rebuilds. The flow
announces state; the UI does not poll “are you loading?”. |
| Channel (OmegaChannel) | Global event bus. Single communication point: anyone can
emit(OmegaEvent) and anyone can subscribe to events.
Decouples who emits from who listens.
|
| Agent (OmegaAgent) | Autonomous logic unit with an id, channel and behavior engine. Reacts
to events (and optionally to direct intents). The behavior returns a reaction
(action + payload); the agent executes it in onAction and can emit new
events. Encapsulates logic that is testable without Flutter. |
| Flow (OmegaFlow) | Business flow (login, checkout, etc.) with states (idle, running, paused,
sleeping, ended). Only in running does it process events and intents.
It orchestrates: receives intents from the UI, emits events for agents, listens to
events, emits expressions for the UI and emits navigation intents. |
| FlowManager (OmegaFlowManager) | Registers flows, activates/pauses them (activate,
switchTo) and routes intents only to those in running.
Connects the channel to the navigator (wireNavigator) so that
"navigate.*" and "navigation.intent" change screens. |
| Behavior (behavior engine) | Defines when an agent reacts and which action to return. Composed of rules
(condition + reaction). Evaluates the context (event or intent) and returns the
first OmegaAgentReaction that matches.
|
| Snapshot | State “photo”: of a flow (OmegaFlowSnapshot) or the whole app
(OmegaAppSnapshot). Includes flowId, state, memory and last
expression. Used for debugging, persistence (save/restore on close/open) and
time‑travel style tools.
|
| Offline queue | Queue of pending intents when the app is offline
(OmegaQueuedIntent, OmegaOfflineQueue,
OmegaMemoryOfflineQueue). A flow enqueues intents on connectivity
failures and another service retries them when the connection comes back. See the
Offline-first (intent queue) section in doc/GUIA.md. |
Everything Omega offers
A summary of the framework’s capabilities and tools.
Communication and semantics
- Global event bus (
OmegaChannel): decoupled emit and listen. - Events with name and payload; typed names with
OmegaEventNameandOmegaEvent.fromName. - Intents with name and payload; typed names with
OmegaIntentNameandOmegaIntent.fromName. - Typed payload access:
payloadAs<T>()on events, intents and expressions.
Agents and behavior
- Autonomous agents (
OmegaAgent) with id, channel and behavior engine. - Rule engine (
OmegaAgentBehaviorEngine):addRule(condition, reaction). - Evaluation context (
OmegaAgentBehaviorContext): event, intent, state. - Reaction:
OmegaAgentReaction(action, payload)executed inonAction. - Agent protocol: direct messages (
send) and broadcast.
Flows and orchestration
- Business flows (
OmegaFlow) with states: idle, running, sleeping, paused, ended. OmegaFlowManager:registerFlow,activate,switchTo,handleIntent, wireNavigator.- Expressions toward the UI:
emitExpression(type, payload); the UI listens toexpressions. - Per‑flow memory (
memory) that persists and is included in the snapshot. - Snapshot per flow and for the whole app;
toJson/fromJsonfor persistence.
UI, navigation and bootstrap
OmegaScope: injects channel and flowManager;OmegaScope.of(context).OmegaBuilder: widget that reacts to a channel event (optionally filtered byeventName).- Decoupled navigation:
"navigate.id"(pushReplacement),"navigate.push.id"(push);payload → arguments. - Typed routes:
OmegaRoute.typed<T>androuteArguments<T>(context). OmegaConfigandOmegaRuntime.bootstrap: single bootstrap point; optionalinitialFlowId.
Persistence, inspector and CLI
- Persistence:
getAppSnapshot → toJson → save; on open,fromJson → restoreFromSnapshot.OmegaSnapshotStorage(save/load) can be implemented with disk or backend. - Inspector: debug panel (
OmegaInspector) with latest events and flow snapshots. On web:OmegaInspectorLauncheropens a separate window;OmegaInspectorReceivershows the data viaBroadcastChannel. - CLI:
omega doc(opens this documentation),omega init(createsomega_setup.dart),omega g ecosystem <Name>,omega g agent <Name>,omega g flow <Name>,omega validate. Generates files in the current directory and updatesomega_setup.dart.
Going beyond traditional limits
The Glass Ceiling of BLoC
Structural rigidity. Strong coupling between Streams and Widgets. Exponential complexity in large apps.
The Riverpod Maze
Hard‑to‑trace flows. Provider fragmentation. Technical learning curve on top of business semantics.
The Paradigm Shift
In Omega, business logic does not “live” in the UI. Logic lives in Autonomous Agents that operate independently and communicate through a Semantic Layer.
UI as a Mirror
The interface is a “dumb” mirror that reflects the expressions of the business process.
Actor‑Based
Inspired by the Elixir/Erlang actor model for total isolation of responsibilities.
Scalable‑First
Designed for large teams where modularity is the only path to success.
Evolutionary Architecture
Distributed Intelligence
Autonomous agents reduce load on the main thread and decouple logic from the widget lifecycle.
Reactive Global Bus
Asynchronous communication channels allow 100% observability of system activity.
Semantic Layer
Intents and Expressions remove direct coupling between user intent and system response.
Decoupled Architecture
// The Agent: brain of the logic
class AuthAgent extends OmegaAgent {
void _login(credentials) {
emit("auth.login.success", payload: user);
}
}
// The Flow: navigation orchestrator
class AuthFlow extends OmegaFlow {
void onEvent(ctx) {
if (ctx.event?.name == "auth.login.success") {
emitExpression("success");
navigate("home");
}
}
}
Atomic Decoupling
Business code does not mention widgets, contexts or routes. It is pure logic, 100% portable and testable in seconds without emulators.
High‑level view of Omega
High‑level diagram showing how the UI, agents, flows, event channel, FlowManager, navigator and CLI interact.
Omega vs BLoC vs Riverpod
Observable, persistable and reproducible state; agents, flows and intents at the core; the UI only reflects. With snapshot, inspector and persistence/restore.
| Feature | Omega Architecture | BLoC / Riverpod |
|---|---|---|
| Logic autonomy | ✔ Independent agents | ✘ Dependent on UI/Providers |
| Semantic traceability | ✔ Native (event bus) | ✘ Manual (debug prints) |
| Decoupled navigation | ✔ Yes (via flows) | ✘ No (via BuildContext) |
| Team scalability | ✔ Modular (micro‑agents) | ✘ Prone to “spaghetti” |
Omega vs BLoC: In Omega, logic lives in agents that do not know the UI; in
BLoC it lives in Blocs tied to Streams and widgets. Omega decouples navigation (intents);
BLoC usually uses BuildContext.
Omega vs Riverpod: Riverpod is very flexible
(providers, ref); Omega fixes a model (agents + flows + channel) and gives explicit
traceability (named events/intents). Navigation in Omega does not depend on
context.
For a detailed table and
when to choose each one, see doc/COMPARATIVA.md in the repo.
When to choose Omega
Choose Omega if...
You want business logic outside the UI and easy to test without Flutter, decoupled navigation, teams that need a clear structure (agents, flows, intents) or apps with high complexity.
Choose BLoC or Riverpod if...
You prefer something very widely adopted (documentation, examples, community), you are fine with events → states → UI or flexible providers and you do not need the agents model or the intents layer.
Omega does not compete in popularity; it
differentiates itself through agents + behavior + channel + flows + intents and
navigation without BuildContext. It is architecture, not just state management.
The importance of Omega
A framework that brings together clear architecture, real decoupling, and tools available from day one.
Omega is not “just another BLoC”. It is a way to organize the application where the business logic lives in agents, orchestration happens in flows, and the UI simply reflects what the system decides. This reduces bugs, speeds up testing, and allows the application to scale easily with the team.
Clarity from day one
You always know where things belong: agents for logic, flows for orchestration, and intents for communication. No guessing which Provider or Bloc holds each rule.
Truly testable
The logic does not depend on Flutter. You can test agents
and flows with pure unit tests, without pumpWidget
or context mocks.
Scalable by design
Ecosystems (agent + flow + behavior + UI) allow multiple developers to work on features without interfering with each other. The CLI also generates a consistent structure.
Why it is worth using
Less coupling, less technical debt
The UI does not know about routes or navigation contexts. Flows emit intents, and the navigator reacts. Changing screens or flows does not break the business logic.
Clear traceability
Events and intents have names and payloads. You can easily track who requested what and who responded, without relying on prints or blind debugging.
Centralized configuration
The omega_setup.dart file gathers agents,
flows, and routes of the application. A quick look
lets you understand how the entire app is structured.
Low investment, high benefit
With omega init and
omega g ecosystem the structure is generated
automatically. This lets you focus on business rules
and user experience instead of building layers manually.
In summary: Omega is worth using when you want an architecture that scales with complexity, is easy to test, and allows the whole team to understand the system without getting lost in scattered Providers or Blocs.
About the software
Omega is a reactive and agent‑based framework for Flutter: business logic lives in agents and flows that communicate through an event channel; the UI only emits intents and reacts to events and expressions.
Short definition: In Omega, an event = "something that happened" (emitted to the channel). An intent = "I want this to happen" (emitted by the UI; the FlowManager distributes it to flows in the running state). An expression = message from the flow to the UI ("loading", "success", "error"). Agents and flows listen to events; flows also receive intents and emit expressions and navigation intents.
Reactive agents
Autonomous entities with id, channel and behavior engine. They react to system events
(and to intents if the flow delegates to them). They execute logic in
onAction and emit new events. Testable without Flutter.
Behavior engine
Set of rules (condition + reaction). It evaluates the context (event or intent) and
returns the first matching OmegaAgentReaction. This way the agent is not a
giant switch; it is composed by rules.
Event‑driven
Everything goes through OmegaChannel: emit(OmegaEvent) and
subscription to events. Agents and flows subscribe; the UI can use
OmegaBuilder to react to a specific event.
Flow management
OmegaFlow orchestrates a use case (login, checkout). It has states (idle,
running, paused, sleeping, ended); only in running it processes events and
intents. OmegaFlowManager registers flows, activates/pauses them and
distributes intents. Several flows can be active at the same time with
activate(id); switchTo(id) leaves only one active.
Semantic intents
OmegaIntent represents a named request (e.g. "auth.login", "navigate.home")
with a payload. The UI does not call methods; it emits intents. For typed names: an enum
that implements OmegaIntentName and
OmegaIntent.fromName(AppIntent.xxx, payload: ...). For navigation, the
intent payload arrives at the screen as arguments (with
OmegaRoute.typed<T> the view receives the type directly).
Examples by use case
Typical code for the most common scenarios.
Production sample app (full Omega in action): Kashira — yefersonsegura.com/projects/kashira/
Emit an event and listen to it (channel)
final channel = OmegaChannel();
channel.emit(OmegaEvent.fromName(AppEvent.userUpdated, payload: user));
channel.events.listen((e) {
if (e.name == AppEvent.userUpdated.name) {
final u = e.payloadAs<User>();
if (u != null) refreshUI(u);
}
});
The UI requests login (intent + flow + agent)
// On the login screen
scope.flowManager.handleIntent(
OmegaIntent.fromName(AppIntent.authLogin, payload: LoginCredentials(email: e, password: p)),
);
// The flow in onIntent emits "loading" and delegates to the agent
channel.emit(OmegaEvent.fromName(AppEvent.authLoginRequest, payload: ctx.intent!.payload));
// The agent in onAction calls the API and emits success/error
emit("auth.login.success", payload: LoginSuccessPayload(token: t, user: u));
Navigate to a screen with typed data
// From the flow, after successful login
channel.emit(OmegaEvent.fromName(
AppEvent.navigationIntent,
payload: OmegaIntent.fromName(AppIntent.navigateHome, payload: userData),
));
// Registration of a typed route (in omega_setup)
navigator.registerRoute(OmegaRoute.typed<LoginSuccessPayload>(
id: "home",
builder: (context, userData) => HomePage(userData: userData),
));
// In HomePage you receive userData already as LoginSuccessPayload
Save and restore state (persistence)
// On close or at a save point
final snapshot = flowManager.getAppSnapshot();
await prefs.setString("omega_state", jsonEncode(snapshot.toJson()));
// When opening the app
final loaded = prefs.getString("omega_state");
if (loaded != null) {
final snapshot = OmegaAppSnapshot.fromJson(jsonDecode(loaded));
flowManager.restoreFromSnapshot(snapshot);
}
Show the inspector in debug
if (kDebugMode)
Stack(
children: [
MyApp(),
Positioned(right: 0, top: 0, child: OmegaInspector(eventLimit: 20)),
],
)
// On web: OmegaInspectorLauncher in the AppBar opens the separate window
Kashira: example in production
POS (point of sale) system built with Omega Architecture. Small and medium stores: sales, inventory, products and real‑time reports.
Live app: yefersonsegura.com/projects/kashira/
Vision
Register sales, manage inventory, handle products and consult reports from an intuitive app. Control daily operations, best‑selling products, up‑to‑date stock and sales history. Simple management to improve organization and decision‑making.
Why Omega in Kashira
- Single channel: all communication through
OmegaChannel(emit/onEvent). - Agents and flows per domain: Auth, Theme, Home, Sales, Inventory, Products (Agent + Flow for each one).
- Behaviors: rules that translate events into actions
(
OmegaBehaviorEngine). - Declarative navigation: routes in configuration; the UI emits intents, Omega resolves to Navigator.
- Typing:
KashiraEvent,KashiraIntent,OmegaRoute.typed<T>(),payloadAs<T>(). - Snapshots: persistence of flow state when reopening the app.
- Inspector: in debug, window/dialog for events and snapshots.
Omega components used
| Component | Use in Kashira |
|---|---|
OmegaChannel |
Single event channel; emission from UI and agents. |
OmegaAgent |
Auth, Theme, Home, Products, Inventory, Sales. |
OmegaFlow |
One flow per domain; listens to events and emits expressions to the UI. |
OmegaFlowManager |
Flow registration and activation; activate(flowId),
restoreFromSnapshot.
|
OmegaBehaviorEngine |
Behaviors per agent: auth, theme, sales, inventory, products, home. |
OmegaNavigator |
Routes: login, home, sales, inventory, productForm, etc. |
OmegaRoute / OmegaRoute.typed<T>() |
productForm route receives a typed Producto?. |
OmegaEvent / OmegaIntent |
Typed names (KashiraEvent, KashiraIntent). |
OmegaScope |
Provides channel, flowManager,
initialFlowId.
|
OmegaAppSnapshot / OmegaSnapshotStorage |
Save/load state when pausing/closing the app. |
OmegaInspectorLauncher / OmegaInspectorReceiver |
Debugging of events and snapshots (debug). |
Flows and agents per domain
| Flow / Agent | Responsibility |
|---|---|
| Theme | Light/dark mode; persistence in ThemeStorage. |
| Auth | Login, logout, session restore; navigation after login. |
| Home | Entry point of the dashboard. |
| Sales | Products for sale, sale creation (simulated service). |
| Inventory | Stock summary, movements (simulated service). |
| Products | Catalog and categories; navigation to product form. |
Events and intents (typed)
Centralized in kashira_semantics.dart: events
(KashiraEvent) such as navigationIntent, themeRequest,
authLoginRequest, productosLoadRequest, ventasCrearVenta,
etc.; intents (KashiraIntent) such as navigateLogin,
navigateHome, navigatePushProductoForm, authLogin, etc.
Usage:
OmegaEvent.fromName(KashiraEvent.navigationIntent, payload: OmegaIntent.fromName(KashiraIntent.navigateHome)).
Routes
Defined in omega_setup.dart: login,
register, home, ventas, inventory,
productoForm (typed with Producto?).
Tech stack
Flutter (mobile + web), omega_architecture ^0.0.26,
shared_preferences (mobile/desktop), web (localStorage on web for
session, theme and snapshots).
Main features
- Sales: fast registration, cart, discounts, category search, currency S/.
- Inventory: stock summary, alerts, movements, adjustments.
- Products: catalog (code/SKU, category, prices), create/edit form (typed
route with
Producto?). - Theme: light/dark with Omega (ThemeFlow/ThemeAgent) and persistence.
- Session: login and restore; persistence depending on platform.
- Reports: sales history and views for analysis.
Project structure (Kashira)
lib/
├── main.dart # Omega bootstrap, theme, snapshots, inspector
├── core/ # theme, storage (session/theme/snapshot io+web), utils
├── omega/
│ ├── omega_setup.dart # OmegaConfig: agents, flows, routes
│ └── kashira_semantics.dart # KashiraEvent, KashiraIntent
└── features/
├── auth/ # AuthAgent, AuthFlow, auth_behavior, auth_page
├── theme/ # ThemeAgent, ThemeFlow, theme_behavior
├── home/ # HomeAgent, HomeFlow, home_behavior, home_page
├── ventas/ # VentasAgent, VentasFlow, ventas_behavior, ventas_page, service
├── inventory/ # InventoryAgent, InventoryFlow, inventory_behavior, inventory_page, service
└── productos/ # ProductosAgent, ProductosFlow, producto_form_page, service, producto_model
Goal: accessible and reliable solution to digitize small businesses and optimize sales and inventory, with clear and maintainable architecture thanks to Omega.
Core concepts
Summary of each piece of the system and its role.
| Concept | Description |
|---|---|
| OmegaChannel | Central event bus. emit(OmegaEvent) to publish;
events (Stream) to subscribe. All agents and flows use the same
channel. Whoever creates it must call dispose() on shutdown.
|
| OmegaEvent | Represents "something that happened". Fields: id, name,
payload. Create with
OmegaEvent.fromName(OmegaEventName, payload) for typed names. Read the
payload with type: event.payloadAs<T>().
|
| OmegaIntent | Action request with name and payload. The UI emits intents
via flowManager.handleIntent(intent). For navigation the payload is
passed as route arguments. Typed names:
OmegaIntent.fromName(OmegaIntentName, payload).
|
| OmegaAgent | Autonomous logic unit: id, channel,
behavior. Subscribes to the channel; the behavior evaluates the context
and returns an OmegaAgentReaction; the agent executes in
onAction(action, payload) and can emit(name, payload).
Call dispose() when closing.
|
| OmegaAgentBehaviorEngine | Rule engine. addRule(OmegaAgentBehaviorRule(condition, reaction)).
evaluate(OmegaAgentBehaviorContext) returns the first reaction whose
condition is met, or null.
|
| OmegaFlow | Business flow with states (idle, running, sleeping, paused, ended). Only in
running it processes onEvent and onIntent.
Emits expressions to the UI with emitExpression(type, payload); the UI
listens to expressions. It has memory (map) and
getSnapshot() / restoreMemory().
|
| OmegaFlowManager | Registers flows with registerFlow(flow). activate(id)
activates without pausing others; switchTo(id) activates one and pauses
the rest. handleIntent(intent) sends the intent to all flows in the
running state. wireNavigator(navigator) connects the channel to the
navigator. getAppSnapshot() and
restoreFromSnapshot(snapshot) for persistence.
|
| OmegaFlowExpression | Message from the flow to the UI: type ("loading", "success", "error")
and payload. Read with type: expr.payloadAs<T>(). The
UI subscribes to flow.expressions.
|
| OmegaScope / OmegaBuilder | OmegaScope injects channel and flowManager; any child uses
OmegaScope.of(context). OmegaBuilder is a widget that rebuilds when an
event arrives (optionally filtering by eventName).
|
| OmegaNavigator / OmegaRoute | Navigator translates "navigate.id" (pushReplacement) and "navigate.push.id" (push);
the intent payload goes to RouteSettings.arguments. Routes with
registerRoute(OmegaRoute).
OmegaRoute.typed<T>(id, builder: (context, T? args)) lets the
screen receive the type without casting; alternatively
routeArguments<T>(context).
|
Use cases
High‑complexity apps
Multiple flows (auth, checkout, onboarding) with decoupled logic and clear traceability.
Large teams
Modularity by ecosystems (agent + flow + behavior + UI). Each feature can be developed in isolation.
Testing without UI
Business logic in agents and flows, 100% testable without emulators or widgets.
Decoupled navigation
Flows emit navigation intents; the navigator reacts without depending on
BuildContext.
Installation
In your host app (the
Flutter project that uses Omega), add the dependency. The omega_setup.dart file is
created in your app with omega init, it does not come inside the library. There you
define createOmegaConfig(OmegaChannel) with the list of agents, flows and routes
that the runtime will register.
Add to your pubspec.yaml
(from pub.dev):
dependencies:
omega_architecture: ^0.0.26
Complete example in the package: The example/ folder contains an
app with a login flow: login screen that emits intents with
LoginCredentials, agent that validates and emits success/error with
LoginSuccessPayload, flow that reacts in onIntent and
onEvent, navigation to home with typed route
OmegaRoute.typed<LoginSuccessPayload> and use of
payloadAs<T>() in events and expressions. Run with
cd example && flutter run.
Omega CLI
The CLI runs in your app (the one that uses omega_architecture). From a project that depends on omega_architecture: dart run omega_architecture:omega <command> [options]
Why
Open the official docs from the terminal without searching the web or bookmarking the URL.
Instruction
dart run omega_architecture:omega doc
Concept
Opens the official Omega web documentation in the browser (online). Does not create or modify any files.
Example (success)
Opening documentation: http://yefersonsegura.com/proyects/omega/
Why
Your app needs one central place to register routes, agents and flows; init creates that file so you don’t have to write the boilerplate by hand.
Instruction (both forms)
dart run omega_architecture:omega init
dart run omega_architecture:omega init --force
Without --force: creates omega_setup.dart only if it does not exist; if it already exists, the CLI reports an error (so you do not overwrite by mistake). With --force: overwrites the existing file (use when you want to reset or regenerate the setup).
Concept
Creates lib/omega/omega_setup.dart in your app with an empty OmegaConfig (agents, flows, routes). Run from the project root. By default the command is safe (no overwrite); use --force only when you intend to replace the current file.
Example (success)
Omega setup created.
Project root: C:\...\my_app
File: C:\...\my_app\lib\omega\omega_setup.dart
Example (failure)
Error: omega_setup.dart already exists.
Use --force to overwrite.
Why
A full feature (e.g. Auth, Orders) usually needs an agent, a flow, a behavior and a page; this command creates all four and wires them in omega_setup.dart so you can focus on logic instead of boilerplate.
Instruction
dart run omega_architecture:omega g ecosystem <Name>
Concept
Generates agent, flow, behavior and page in the current directory. Registers agent and flow in omega_setup.dart. Run from the folder where you want the files (e.g. lib/ or lib/features/).
Example (success)
Creating in current directory: C:\...\my_app\lib
Ecosystem Auth created.
Path: C:\...\my_app\lib\auth
Registered Auth (agent, flow) in omega_setup.dart
Example (failure)
Error: omega_setup.dart not found.
Run from app root: omega init
Why
Sometimes you need only a new agent (and its behavior) for an existing flow or a feature that doesn’t need a full ecosystem; this avoids generating an extra flow and page.
Instruction
dart run omega_architecture:omega g agent <Name>
Concept
Generates only agent + behavior in the current directory. Updates only the agent import and registration in omega_setup.dart (does not touch the flow).
Example (success)
Agent Orders created.
Path: C:\...\my_app\lib\orders
Why
When you need only a new flow (orchestrator) without a new agent or page, this creates just the flow and registers it in omega_setup.dart without touching the rest.
Instruction
dart run omega_architecture:omega g flow <Name>
Concept
Generates only flow in the current directory. Updates only the flow import and registration in omega_setup.dart (does not touch the agent).
Example (success)
Flow Profile created.
Path: C:\...\my_app\lib\profile
Instruction
dart run omega_architecture:omega validate [path]
Concept
Checks omega_setup.dart: createOmegaConfig, OmegaConfig, agents:, and no duplicate agent/flow registrations. Starts from the bash directory (or optional path).
Example (success)
Directorio (bash): C:\...\my_app
Valid.
File: C:\...\my_app\lib\omega\omega_setup.dart
Agents: 2, Flows: 3
Example (failure)
Error: Duplicate flow registration: Auth.
Remove duplicate XFlow(channel) from omega_setup.dart.
Why
Recorded sessions (events + snapshot) can be saved as JSON; trace view and trace validate let you inspect or validate those files from the CLI (debugging, CI, or sharing a bug report) without running the app.
Instruction
dart run omega_architecture:omega trace view <file.json>
dart run omega_architecture:omega trace validate <file.json>
Concept
Trace = JSON file with a recorded session (channel events and optional initial snapshot). Built by OmegaTimeTravelRecorder in your app when you call stopRecording(); the developer chooses where to save the JSON (mobile: path_provider; web: download). trace view shows a summary (events, snapshot). trace validate checks the structure; exit 0 if valid, 1 otherwise. Used for debugging, reproducing bugs, or sharing a case.
Example: export session to JSON
import 'dart:convert';
final session = recorder.stopRecording();
final jsonString = jsonEncode(session.toJson());
// Mobile: path_provider + File(path).writeAsString(jsonString)
// Web: blob + <a download> (see doc/TIME_TRAVEL.md)
Full code (mobile/web) in TIME_TRAVEL.md → “Export session to JSON (trace file)”.
Example view (success)
Trace: C:\...\trace.json
Events: 42
Initial snapshot: yes
Example validate (success)
Valid trace file.
Path: C:\...\trace.json
Example (failure)
Error: Invalid trace structure (expected 'events' list and optional 'initialSnapshot').
Why
One command to see if your Omega setup is valid, how many agents/flows you have, and optional hints (e.g. flows/agents without a contract), so you can fix issues before they cause problems at runtime.
Instruction (both forms)
dart run omega_architecture:omega doctor
dart run omega_architecture:omega doctor <path>
Without path: uses the current directory (bash CWD) to find the app root. With path: starts the search from that path (e.g. omega doctor example when you are at the package root and want to check the example/ app).
Concept
Project health: validates omega_setup.dart, counts agents and flows, optionally lists flows/agents without a contract. By default it starts from the current directory; in a real project there is no example/ folder. If you are in lib/, it looks for the omega/ folder there. The optional <path> tells the CLI where to start looking (useful in repos with an example/ or multiple apps).
Example (success)
Directory (bash): C:\...\my_app\lib
Omega Doctor
Setup: C:\...\my_app\lib\omega\omega_setup.dart
Agents: 2, Flows: 3
Health check passed.
Example (errors)
Error: Duplicate flow registration: Auth.
Remove duplicate XFlow(channel) from omega_setup.dart.
Fix the issues above and run omega doctor again.
Example (optional warnings)
Omega Doctor
Setup: ...
Agents: 2, Flows: 3
Optional (contracts):
Flow without contract: ...\lib\orders\orders_flow.dart
Agent without contract: ...\lib\provider\provider_agent.dart
Tip: add a contract getter for clearer semantics and debug warnings.
Health check passed.
Why
Bootstrap a professional Flutter project with Omega in seconds, with all the initial wiring and optionally business logic generated by AI.
Instruction
omega create app <Name> [--kickstart "description"] [--provider-api]
Steps for Success
- Activate command: Run
dart pub global activate omega_architecturefirst. - Configure PATH: If
omegais not recognized, add Dart'sbinfolder to your environment variables. - Without AI: Run the simple command for a clean architecture setup.
- With AI: Set your
OMEGA_AI_API_KEYfirst. The AI will write real business modules based on your description.
Concept
Orchestrates flutter create, adds omega_architecture, runs omega init, and generates a clean main.dart with Omega's bootstrap. If you use --kickstart, the AI analyzes your idea and generates custom modules (agents, flows, and UI) specific to your app. Must be executed outside existing projects.
Example (AI)
omega create app my_store --kickstart "e-commerce with cart and payments" --provider-api
Why
Diagnose traces with optional AI assistance while keeping a zero-cost offline mode as default/fallback.
Instruction
dart run omega_architecture:omega ai doctor
dart run omega_architecture:omega ai env
dart run omega_architecture:omega ai explain <file.json>
dart run omega_architecture:omega ai explain <file.json> --json
dart run omega_architecture:omega ai explain <file.json> --provider-api
dart run omega_architecture:omega ai explain <file.json> --stdout
dart run omega_architecture:omega ai coach start "<feature>"
dart run omega_architecture:omega ai coach audit "<feature>"
dart run omega_architecture:omega ai coach module "<Name>" --template advanced
Concept
ai explain uses the same trace structure as omega trace (events list + optional initialSnapshot). Without flags it runs local heuristics (top events, namespaces, error/repetition patterns). With --provider-api, it tries provider mode (OpenAI today) and automatically falls back to offline on config/network failure.
Default output: ai explain and ai coach write a temporary report to .dart_tool/omega_ai_temp and open it; use --stdout for direct console output.
ai coach start builds an implementation guide (steps, required artifacts and validation checks). ai coach audit audits a real feature and returns score, findings and gaps (wiring, contracts, tests, etc.). ai coach module generates a complete ecosystem using optimized templates (WorkflowFlow, StatefulAgent, etc.).
Future Capabilities (WIP)
ai coach fix-gaps— Automatically creates files and wiring detected in audit.ai coach generate-tests— Generates real test cases by analyzing flow/agent logic.ai suggest-contracts— Proposes declarative contract definitions by analyzing code.ai review-architecture— Senior-level architectural report (couplings, naming, complexity).
Response language
Provider and offline output follow the system locale (country/language). You can override it with OMEGA_AI_LANG or OMEGA_AI_LANGUAGE.
Environment variables
OMEGA_AI_ENABLED=true|false
OMEGA_AI_PROVIDER=openai|anthropic|gemini|ollama|none
OMEGA_AI_API_KEY=...
OMEGA_AI_MODEL=...
OMEGA_AI_BASE_URL=...
OMEGA_AI_LANG=es|en|pt|...
Example (provider)
dart run omega_architecture:omega ai explain trace.json --provider-api
Example (coach audit)
dart run omega_architecture:omega ai coach audit "auth"
Global options: -h, --help · -v, --version
Other documentation
In the repository (doc/) there are additional guides and references:
- CONTRACTS.md — Declarative contracts (OmegaFlowContract, OmegaAgentContract), examples and using the
contractgetter for semantics and debug warnings. - TIME_TRAVEL.md — Recording and replaying sessions with OmegaTimeTravelRecorder and OmegaRecordedSession; replay for debugging.
- GUIA.md — Usage guide: channel, agents, flows, navigation, persistence, Inspector, offline-first, time-travel.
- ROADMAP.md — Framework roadmap, future ideas and status of features.
- TESTING.md — How to test agents and flows without Flutter, and tests with OmegaTimeTravelRecorder.
- ARQUITECTURA.md — Architecture vision and design decisions.
- MEJORAS.md — History of improvements applied (steps 1–7, etc.).
This web is the main documentation; the doc/ folder complements it with detail and examples in the repo.
Usage: agent and behavior
The agent subscribes to the channel; when an
event (or an intent) arrives, the behavior evaluates the context and returns a
reaction (action + payload); the agent executes it in onAction. You can use rules
with addRule instead of overriding evaluate.
// Option 1: rules (recommended)
class AuthBehavior extends OmegaAgentBehaviorEngine {
AuthBehavior() {
addRule(OmegaAgentBehaviorRule(
condition: (ctx) => ctx.event?.name == AppEvent.authLoginRequest.name,
reaction: (ctx) => OmegaAgentReaction("doLogin", payload: ctx.event?.payload),
));
}
}
class AuthAgent extends OmegaAgent {
AuthAgent(OmegaChannel c) : super(id: "Auth", channel: c, behavior: AuthBehavior());
@override void onMessage(OmegaAgentMessage msg) {}
@override
void onAction(String action, dynamic payload) {
if (action == "doLogin") _login(payload);
}
void _login(dynamic payload) {
final creds = payload is LoginCredentials ? payload : null;
if (creds == null) { emit("auth.login.error", payload: OmegaFailure(...)); return; }
// API call... then:
emit("auth.login.success", payload: LoginSuccessPayload(token: t, user: u));
}
}
Flow
Channel emits event → agent receives → behavior evaluates context (event/intent) → returns
OmegaAgentReaction("doLogin", payload) →
onAction("doLogin", payload) executes the logic (e.g. calling an API) and
emits "auth.login.success" or "auth.login.error".
Typed payload
In the agent you can check payload is LoginCredentials or receive the intent
from the flow and use intent.payloadAs<LoginCredentials>(). Emit
events with typed payloads (e.g. LoginSuccessPayload) so that the flow and
the UI use payloadAs<T>().
Integrate Omega into your host app
Steps: 1) Bootstrap the runtime. 2)
OmegaScope with channel, flowManager and
initialFlowId. 3)
MaterialApp with navigatorKey. 4) On the first frame: activate the initial flow and
emit the initial navigation (e.g. to login). Optional: on web, show only the Inspector if the URL
contains ?omega_inspector=1.
1. main.dart — Bootstrap and OmegaScope
// lib/main.dart
void main() {
// Optional: on web, inspector window (OmegaInspectorLauncher opens with ?omega_inspector=1)
if (Uri.base.queryParameters['omega_inspector'] == '1') {
runApp(MaterialApp(home: const OmegaInspectorReceiver()));
return;
}
final runtime = OmegaRuntime.bootstrap(createOmegaConfig);
runApp(
OmegaScope(
channel: runtime.channel,
flowManager: runtime.flowManager,
initialFlowId: runtime.initialFlowId, // e.g. "authFlow"
child: MyApp(navigator: runtime.navigator),
),
);
}
class MyApp extends StatelessWidget {
final OmegaNavigator navigator;
const MyApp({super.key, required this.navigator});
@override
Widget build(BuildContext context) {
return MaterialApp(
navigatorKey: navigator.navigatorKey,
home: const _RootHandler(),
);
}
}
2. RootHandler — Activate initial flow and navigate
class _RootHandler extends StatefulWidget {
const _RootHandler();
@override
State<_RootHandler> createState() => _RootHandlerState();
}
class _RootHandlerState extends State<_RootHandler> {
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
final scope = OmegaScope.of(context);
// 1) Activate the initial flow (defined in createOmegaConfig with initialFlowId)
if (scope.initialFlowId != null) {
scope.flowManager.switchTo(scope.initialFlowId!);
}
// 2) Navigate to the first screen (e.g. login) with typed names
final intent = OmegaIntent.fromName(AppIntent.navigateLogin);
scope.channel.emit(
OmegaEvent.fromName(AppEvent.navigationIntent, payload: intent),
);
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: kDebugMode ? AppBar(actions: const [OmegaInspectorLauncher()]) : null,
body: const Center(child: Text("Omega Running")),
);
}
}
3. omega_setup.dart — Config (agents, flows, routes, initialFlowId)
// lib/omega/omega_setup.dart (created with omega init / omega g ecosystem)
OmegaConfig createOmegaConfig(OmegaChannel channel) {
return OmegaConfig(
agents: [AuthAgent(channel), ProviderAgent(channel)],
flows: [AuthFlow(channel), ProviderFlow(channel)],
routes: [
OmegaRoute(id: "login", builder: (context) => const LoginPage()),
OmegaRoute.typed<LoginSuccessPayload>(id: "home", builder: (context, userData) => HomePage(userData: userData)),
],
initialFlowId: "authFlow",
);
}
Summary: createOmegaConfig is defined in
lib/omega/omega_setup.dart (omega init / g ecosystem). It includes
initialFlowId so that the RootHandler activates that flow on the first frame.
Use OmegaIntent.fromName and OmegaEvent.fromName with your enums
(AppIntent, AppEvent) to avoid magic strings. Typed routes with
OmegaRoute.typed<T> so that the screen receives the payload with type.
When closing the app, whoever holds a reference to the runtime can call
channel.dispose() and flowManager.dispose() if needed.
Flutter: OmegaScope and OmegaBuilder
OmegaScope provides the channel and the flow manager to the entire UI. OmegaBuilder lets a part of the tree react to a channel event without the screen knowing the flow.
OmegaScope (dependency injection)
Wraps the app (usually in main) with channel,
flowManager and optionally initialFlowId. Any child can access
it with OmegaScope.of(context) to call handleIntent, emit
events or get the flow and listen to expressions.
runApp(
OmegaScope(
channel: runtime.channel,
flowManager: runtime.flowManager,
initialFlowId: runtime.initialFlowId,
child: MaterialApp(...),
),
);
// In a screen:
final scope = OmegaScope.of(context);
scope.flowManager.handleIntent(...);
OmegaBuilder (UI reactive to an event)
Widget that rebuilds when an event arrives at the channel. If you specify
eventName, it only reacts to that name. Useful to show a global error
banner ("auth.login.error") or a "user.updated" message without the screen knowing the
flow. Requires OmegaScope in the tree.
OmegaBuilder(
eventName: AppEvent.authLoginError.name,
builder: (context, event) {
final err = event?.payloadAs<OmegaFailure>();
return err != null ? Text(err.message) : SizedBox.shrink();
},
)
Using the Inspector (debug only)
Three options; in release all are no-op.
- 1. Overlay:
Stack(children: [MyContent(), Positioned(..., child: OmegaInspector())])withkDebugMode. - 2. Launcher:
AppBar(actions: [OmegaInspectorLauncher()])— on web opens a remote window withOmegaInspectorReceiver(BroadcastChannel); on desktop/mobile opens a dialog. - 3. Online Inspector (VM Service + web): on Android/iOS/desktop call
OmegaInspectorServer.start(channel, flowManager); the console prints a URL likehttp://yefersonsegura.com/projects/omega/inspector.html#<encoded-VM-URL>. Open it in your desktop browser (or paste the VM Service URL in the input) and the inspector will auto-connect.
Lifecycle of a flow
An OmegaFlow only processes events and intents when it is in the
running state.
Activating a flow or not defines whether it participates in the orchestration.
Flow states
- idle: created but has not started yet. Does not process anything.
- running: active. Receives events/intents and executes
onEvent/onIntent.onStart()is called on entry. - sleeping: keeps memory, but ignores events/intents. Useful to "hibernate" logic.
- paused: temporarily stopped. It does not process anything until it is reactivated.
- ended: finished. Closes its expression stream and releases resources.
Activate and deactivate
flowManager.activate("flowId"): puts the flow inrunningwithout touching the others. You can have several active flows at the same time.flowManager.switchTo("flowId"): activates one and pauses those that were inrunning. Ideal for a single "main" flow.flowManager.activateExclusive("flowId"): similar toswitchTo, but does not validate whether the id exists; it is more "aggressive".- If you do not activate a flow: it stays in
idle, does not process events/intents and itsonStart()is never called.
Pause, sleep and end
flowManager.pause("flowId"): moves the flow topaused. It does not process anything until it is reactivated withactivateorswitchTo.flowManager.sleep("flowId"): callssleep()on the flow (statesleeping). Keeps memory, but is "at rest".flowManager.end("flowId"): callsend()(stateended) and it should no longer be used.flowManager.endAll(): ends all registered flows and clearsactiveFlowId.
Practical consequences
- Only flows in
runningreceiveOmegaIntentfromhandleIntent. - If a screen depends on a flow's expressions, you must make sure to activate it
first (for example in a
RootHandleror after login). - Use
switchTowhen you want a single flow to "own" navigation and the main experience. - Use
activatewhen you want several flows collaborating in parallel (for example, notifications + auth + cart).
Lifecycle and dispose
| Component | Responsibility |
|---|---|
| OmegaChannel | Whoever creates it must call channel.dispose() when closing the app.
|
| OmegaFlowManager | Call flowManager.dispose() to cancel the subscription created by
wireNavigator.
|
| OmegaAgent | Call agent.dispose() to cancel the subscription to the channel. |
| OmegaScope | Does not dispose; the widget that creates channel and
flowManager must call their dispose() in
State.dispose.
|
Project structure
lib/
├── omega/
│ ├── core/ # Channel, events, intents, types
│ ├── agents/ # OmegaAgent, behavior engine, protocol
│ ├── flows/ # OmegaFlow, OmegaFlowManager, expressions
│ ├── ui/ # OmegaScope, OmegaBuilder, navigation
│ └── bootstrap/ # Config, runtime
├── example/ # Complete example
└── omega_architecture.dart # Public exports
Declarative contracts
A contract declares which events a flow listens to, which intents it accepts, and which expression types it emits (and for agents: events and intents). In debug mode, Omega prints a warning in the console when something is received or emitted that is not declared; this helps ensure the data you defined is respected.
Why use it? To document flow/agent boundaries, catch typos or wrong names
in development, and lay the groundwork for strict mode or an Inspector that shows "what this
flow expects". It is optional: if you do not define contract, behavior is
unchanged.
Reference example: The package example/
app implements contracts in AuthFlow and AuthAgent. Run
cd example && flutter run to see login/logout with contracts; in debug, any
event or intent not in the contract will trigger a console warning. Use that app as the main
reference when adding contracts to your own flows and agents.
Flow contract (OmegaFlowContract)
Override contract in your flow and
return an OmegaFlowContract with event names, intent names, and expression
types.
class AuthFlow extends OmegaFlow {
AuthFlow(OmegaChannel c) : super(id: 'authFlow', channel: c);
@override
OmegaFlowContract? get contract => OmegaFlowContract.fromTyped(
listenedEvents: [AppEvent.authLoginSuccess, AppEvent.authLoginError],
acceptedIntents: [AppIntent.authLogin, AppIntent.authLogout],
emittedExpressionTypes: {'loading', 'success', 'error'},
);
// ... onEvent, onIntent
}
Agent contract (OmegaAgentContract)
Override contract in your agent with
the events and intents it handles.
@override
OmegaAgentContract? get contract => OmegaAgentContract.fromTyped(
listenedEvents: [AppEvent.authLoginRequest],
acceptedIntents: [AppIntent.authLogin],
);
Empty sets mean no constraint. Validation runs only in kDebugMode; release builds
are unaffected. Full reference: example/ app (AuthFlow, AuthAgent) and
doc/CONTRACTS.md.
Time-travel (record & replay)
You can record a session (channel events + initial snapshot) and replay it to go back to a previous moment: restore the snapshot and re-emit events up to an index. Useful for debugging, demos, or auditing.
Concepts: Record — on start an initial snapshot is saved and each emitted event is appended to a list. Replay — restore the snapshot and re-emit events (or only up to an index) on the channel so the app is in the state it had at that step (time-travel).
Basic usage
final recorder = OmegaTimeTravelRecorder();
recorder.startRecording(channel, flowManager);
// ... user interacts, events are recorded ...
final session = recorder.stopRecording();
// Replay all
recorder.replay(session, channel, flowManager);
// Go to step 5 (time-travel)
recorder.replay(session, channel, flowManager, upToIndex: 5);
OmegaRecordedSession holds initialSnapshot and events. During replay the recorder does not record again. See doc/TIME_TRAVEL.md.
OmegaChannel
Definition: Central event bus. All communication between agents, flows and the
UI goes through the channel. The emitter does not know who is listening; this decouples logic
from the UI. There should only be one channel instance per app (created in
OmegaRuntime.bootstrap and injected via OmegaScope).
| Member | Description |
|---|---|
events |
Event stream. Subscribe to react (agents, flows, OmegaBuilder). |
emit(OmegaEvent event) |
Publishes an event. All events subscribers receive it. |
dispose() |
Closes the channel. Call when closing the app to avoid leaks. |
Example:
channel.emit(OmegaEvent.fromName(AppEvent.authLoginRequest, payload: creds));
channel.events.listen((e) {
if (e.name == AppEvent.authLoginSuccess.name) {
final user = e.payloadAs<User>();
if (user != null) goToHome(user);
}
});
OmegaEvent
Definition: Represents "something that happened" in the system. It has an
id (unique), name (semantic, e.g. "auth.login.success") and
payload (optional data). To avoid magic strings, define an enum that implements
OmegaEventName and use
OmegaEvent.fromName(AppEvent.xxx, payload: data). To read the payload with type
safety: event.payloadAs<User>() (returns null if the type does not match).
| Member | Description |
|---|---|
name |
Event name. Listeners filter by this value. |
payload |
Optional data. Use payloadAs<T>() for typed reading. |
OmegaEvent.fromName(eventName, {payload, id, meta}) |
Factory with typed name. Generates an id if not provided. |
// Create
channel.emit(OmegaEvent.fromName(AppEvent.authLoginSuccess, payload: LoginSuccessPayload(...)));
// Read in listener
final data = event.payloadAs<LoginSuccessPayload>();
OmegaIntent
Definition: Represents an action request with business meaning: "I want to log
in", "I want to go to home". The UI does not call flow or agent methods; it emits an intent with
flowManager.handleIntent(OmegaIntent.fromName(AppIntent.authLogin, payload: creds)).
The FlowManager only sends it to flows that are in the running state. They are also
used for navigation: when the channel emits an event named "navigation.intent" and payload =
OmegaIntent, the navigator executes push/pushReplacement and passes the intent
payload as RouteSettings.arguments. Typed names:
OmegaIntent.fromName(OmegaIntentName, payload). Typed reading:
intent.payloadAs<LoginCredentials>().
| Member | Description |
|---|---|
name |
Intent name (e.g. "auth.login", "navigate.home"). |
payload |
Data. Use payloadAs<T>(). |
OmegaIntent.fromName(intentName, {payload, id}) |
Factory with typed name (OmegaIntentName). |
OmegaEventName
Contract for typed event names. Implement with an enum (e.g.
enum AppEvent implements OmegaEventName { authLoginSuccess('auth.login.success'); @override final String name; })
and use OmegaEvent.fromName(AppEvent.authLoginSuccess, payload: x).
OmegaIntentName
Contract for typed intent names. Implement with an enum and use
OmegaIntent.fromName(AppIntent.authLogin, payload: creds).
OmegaObject
Base class: provides id and meta (metadata map). OmegaEvent,
OmegaIntent and OmegaFailure extend it.
OmegaFailure
Error representation. message (human‑readable) and optional
details. Useful to emit semantic errors through the channel.
OmegaAgent
Autonomous logic unit. It has an id, channel and
behavior.
It subscribes to the channel; the behavior evaluates context and returns reactions; the agent
executes them in onAction. Call dispose() when closing.
| Member | Description |
|---|---|
receiveIntent(OmegaIntent) |
Evaluates the intent with the behavior and executes the reaction in onAction. |
onAction(String action, dynamic payload) |
Abstract. Implement the logic for each action. |
onMessage(OmegaAgentMessage msg) |
Abstract. Response to direct messages. |
emit(String name, {payload}) |
Publishes an event to the channel. |
OmegaAgentBehaviorEngine
Rule engine: given a context (event or intent), it returns the first reaction whose rule matches.
addRule(OmegaAgentBehaviorRule) registers rules;
evaluate(OmegaAgentBehaviorContext) returns an OmegaAgentReaction or null.
OmegaAgentBehaviorRule
Rule: condition(context) indicates whether it applies;
reaction(context) returns the OmegaAgentReaction to execute.
OmegaAgentBehaviorContext
Context passed to evaluate: event, intent and a copy of the agent
state.
OmegaAgentReaction
Result of a rule: action (name) and payload. The agent receives it in
onAction.
OmegaAgentProtocol
Agent registry. register(OmegaAgent); send(OmegaAgentMessage) to a
single agent; broadcast(action, {payload}) to all.
OmegaAgentInbox
FIFO message queue. receive(message) adds; next() returns the next or
null; hasMessages indicates whether there are pending messages.
OmegaAgentMessage
Direct message: from, to, action, payload.
Sent with OmegaAgentProtocol.send.
OmegaFlow
Definition: A flow is a business flow (login, checkout, onboarding). It has
states (OmegaFlowState: idle, running, sleeping, paused, ended) and only when it is
in running does it process channel events and intents (in onEvent and
onIntent). The flow orchestrates: it receives intents from the UI, emits events to
the channel so that agents act, listens to events (e.g. "auth.login.success"), emits expressions
to the UI ("loading", "success", "error") and can emit a navigation intent. The UI does not ask
"are you loading?"; the flow announces the state with emitExpression. The screen
subscribes to flow.expressions. The flow also has memory (key/value
map) that persists while it is active and is included in the snapshot for persistence.
| Member | Description |
|---|---|
expressions |
Stream of expressions towards the UI. |
memory |
Key/value map that persists during the flow. Included in the snapshot. |
emitExpression(String type, {payload}) |
Notifies the UI (loading, success, error). |
getSnapshot() |
Returns OmegaFlowSnapshot (id, state, memory, lastExpression). |
restoreMemory(Map) |
Replaces memory (restore on launch). |
OmegaFlowManager
Manages all flows: registers, activates/pauses, distributes intents to those that are in
running.
wireNavigator(nav) connects the channel to the navigator.
| Member | Description |
|---|---|
registerFlow(OmegaFlow) |
Registers a flow. |
activate(id) |
Activates the flow without pausing the others. Several can be in running. |
switchTo(id) |
Activates one and pauses the rest. A single "main" one. |
handleIntent(OmegaIntent) |
Sends the intent to all flows in running. |
getFlow(id) |
Returns the registered flow. So the UI can listen to expressions. |
getAppSnapshot() |
Snapshot of the entire app (activeFlowId + all flows). |
restoreFromSnapshot(OmegaAppSnapshot) |
Restores memory and active flow. Call when opening the app. |
OmegaFlowState
States: idle, running, sleeping, paused,
ended. Only in running are events and intents processed.
OmegaFlowExpression
Message from the flow to the UI: type ("loading", "success", "error") and
payload. Read payload with type: expr.payloadAs<User>().
OmegaFlowContext
Context in onEvent/onIntent: event, intent and flow
memory.
OmegaFlowSnapshot
Snapshot of a flow: flowId, state, memory, lastExpression. toJson() /
fromJson(Map) for persistence.
OmegaAppSnapshot
Snapshot of the app: activeFlowId and list of OmegaFlowSnapshot. toJson() /
fromJson(Map). Restore with FlowManager.restoreFromSnapshot.
OmegaSnapshotStorage
Optional interface: save(OmegaAppSnapshot) and
load() → Future<OmegaAppSnapshot?>. Implement with disk, SharedPreferences or
a backend.
OmegaScope
InheritedWidget that exposes channel and flowManager (and optionally
initialFlowId). Any child uses OmegaScope.of(context).
OmegaBuilder
Widget that rebuilds when an event arrives at the channel. Optionally filter by
eventName. Requires OmegaScope in the tree.
OmegaNavigator
Converts intents "navigate.id" / "navigate.push.id" into push/pushReplacement.
navigatorKey is assigned to MaterialApp.navigatorKey.
registerRoute(OmegaRoute); handleIntent(OmegaIntent) performs
navigation. The intent payload → RouteSettings.arguments.
OmegaRoute / OmegaRoute.typed / routeArguments
OmegaRoute(id, builder) defines a screen.
OmegaRoute.typed<T>(id, builder: (context, T? arguments)) lets the view
receive the payload with type. If you do not use typed:
routeArguments<T>(context) to read typed arguments.
OmegaInspector / Launcher / Receiver / Server
OmegaInspector: overlay panel with latest channel events and flow snapshots. Debug only (kDebugMode).
OmegaInspectorLauncher: button that on web opens the inspector in a new window (BroadcastChannel); on desktop/mobile opens the overlay in a dialog. In release the button is hidden.
OmegaInspectorReceiver: in the window with ?omega_inspector=1 it shows the inspector (data via BroadcastChannel). In release it shows a "debug only" message.
OmegaInspectorServer: on desktop/mobile and debug only, starts an HTTP server; open the URL printed in the console (e.g. http://localhost:9292) to view the inspector in the browser. On web it is a no-op.
OmegaConfig
Bootstrap configuration: agents, flows, routes,
initialFlowId (optional). Passed to OmegaRuntime.bootstrap.
OmegaRuntime
OmegaRuntime.bootstrap(createOmegaConfig) creates the channel, builds the config,
registers agents in the protocol, flows in the manager, routes in the navigator, connects the
navigator to the channel and returns the runtime. The app uses channel, flowManager, navigator
and initialFlowId to mount OmegaScope and MaterialApp.
Persistence and restore
Concept: A snapshot is a picture of the app state (active flow + state and memory of each flow). You can serialize it to JSON, save it when closing the app (or at save points) and restore it on open. This way the user does not lose context (e.g. current screen and in‑memory data of the flows).
Flow: On close (or at a key point): flowManager.getAppSnapshot() →
snapshot.toJson() → save (SharedPreferences, file with path_provider, backend). On
open: load string/map → OmegaAppSnapshot.fromJson(map) →
flowManager.restoreFromSnapshot(snapshot). The manager restores the
memory of each flow and activates the flow that was active. For persistence to be
correct, the values in memory and in the payloads you save must be JSON‑serializable
(primitives, List, Map).
Optional interface: OmegaSnapshotStorage defines
save(OmegaAppSnapshot) and load() → Future<OmegaAppSnapshot?>.
You can implement it with any storage you want (file, SharedPreferences, API) and call save/load
from your app at the lifecycle points you prefer.
// Guardar
final snapshot = flowManager.getAppSnapshot();
await prefs.setString("omega", jsonEncode(snapshot.toJson()));
// Restaurar al iniciar
final s = prefs.getString("omega");
if (s != null) flowManager.restoreFromSnapshot(OmegaAppSnapshot.fromJson(jsonDecode(s)));
Testing
Agents: Create a channel and test agent that stores what it receives in
onAction. Emit an event or call agent.receiveIntent(intent). After a short delay,
check the variables.
Flows: Create a test flow, call flow.start(), listen to
flow.expressions, call flow.receiveIntent(intent) or emit events.
After a delay, check the received expression. No WidgetTester or Flutter is required.
See doc/TESTING.md in the repo for complete examples.
The Future is Reactive
Omega is not just a library; it is a way of thinking about software. Scalable, testable and ready for the real world.
© 2026 Omega Architecture Project • Yeferson Segura • Leading Flutter Evolution