LFG main service architecture

One backend for sessions, tasks, lasting chats, and event-driven agents

statusDraft for review
A

Decision and system boundary

Make LFG the shared service for manual requests, scheduled work, and incoming messages. The native app, WhatsApp, and email all use this service.

Keep Sessions, Tasks, and Chats as the app's main concepts. Add connections and triggers as supporting configuration, rather than another top-level conversation concept.

Build logical service modules within the existing TypeScript LFG host. Separate processes only where persistent connections or agent execution require them. Avoid a fleet of new microservices.

Use a thin Baileys WhatsApp connector. Reuse existing Claude/Codex execution adapters and Cua tooling. OpenClaw and Hermes are references and optional future adapters, not required dependencies.

This consolidated draft replaces the earlier Hermes-first recommendation. It incorporates the later decisions about LFG ownership, existing chats, Markdown memory, and event triggers.

sessions, tasks, chatsmessages and commandsmailbox eventsdue task occurrencesauthorized worktools and desktopsprogress and outcomesapp updates, replies, notificationsNative appLFG Main ServiceWhatsApp connectorEmail connectorsSchedulerAgent runnersMCP and CuaDelivery

“Main service” means a common application contract and authority. It does not require moving every LFG host or every agent into one process.

B

Domain model: what each object means

Object Meaning Important relationships
Agent profile Assistant identity, instructions, runtime defaults, permitted capabilities One profile can participate in several chats
Chat Lasting discussion and its memory scope Links participants, channel bindings, and execution sessions
Session Provider conversation, transcript, and execution context Can serve a chat, a task run, or direct work
Task Saved work instructions and execution settings Has one or more time, event, or manual triggers
Trigger Condition that starts work References its task, connection, filters, and context policy
Connection Authorized external account Owns credentials, subscription state, sync cursor, and health
Event Durable record of an incoming change or due occurrence Retains source account, conversation, sender, and message identity
Run One accepted unit of work Links origin, session, optional task, outcome, and result destinations
Delivery One intended reply, notification, or result publication Tracks destination and delivery status separately from execution
Space Desktop resource Assigned temporarily through exclusive control leases

Do not redefine a session as one message. A session can contain many turns and can resume after its process stops.

Start with one active execution session per chat. Keep the chat stable if an explicit reset, provider change, or recovery later creates another session.

A group and a private owner chat can use the same agent profile without sharing transcripts or private memory. Profile identity does not grant access across chats.

Generalize scheduled tasks incrementally. Existing task-run records remain the authority for scheduled occurrences. Add a common run reference that points to existing records or new event executions.

Do not require every interactive message to become a saved Task. Direct requests and chat turns can create execution records without task definitions.

C

Services exposed to the app and connectors

This plan proposes the following logical interfaces. Existing routes remain compatible; new names describe the intended contract rather than implemented endpoints.

Service Responsibility Operations exposed
Identity and policy Authenticate users/connectors and determine access Pair identity, resolve principal, check capability
Sessions Manage direct and resumable agent conversations List, create, continue, inspect, stop, fork
Tasks and triggers Save work and determine when it starts Create/edit task; configure time/event trigger; pause; run now
Chats Preserve discussion identity and route messages List, open, submit message, bind channel, inspect history
Connections Maintain email/WhatsApp accounts and subscriptions Connect, disconnect, select monitored scopes, view health
Event admission Save, deduplicate, and classify incoming work Admit event, inspect decision, replay failed processing
Execution Choose a runner and track bounded work Start, observe, cancel, record outcome
Memory Read/write scoped Markdown and build context Remember, recall, correct, forget, inspect source
Actions and approvals Enforce capability grants and action approval Propose, approve, reject, expire
Delivery and notifications Publish results through the right interfaces Reply, notify, stream progress, deep-link, inspect delivery
Resources and artifacts Manage hosts, desktops, files, and captures Acquire/release Space, view artifact, request takeover

The app's Sessions screen consumes Sessions and Execution. Tasks consumes Tasks, Triggers, and run history. Chats consumes Chats, Memory, and Execution.

Connection and monitoring settings show linked accounts, selected groups/mailboxes, active rules, subscription health, and recent decisions. They need no new primary navigation destination.

WhatsApp and email adapters call the same application operations after authentication and normalization. They do not access native session internals or duplicate memory logic.

External participants receive a narrow connector identity. They do not inherit the native app owner's authority merely because they can message the bot.

Keep one command path for submitted work and one authorized event stream for state updates. Reuse LFG's existing event replay where compatible.

D

Three ways work begins

authenticated commandauthorized conversation inputclaimed task occurrencepersisted source eventresolve scope and taskno agent neededpermitted executioncontinue or startprogress, results, approvalsApp requestAdmissionChat messageScheduled occurrenceProvider eventPolicy and routingIgnore or recordWork queueSession runnerOutcomes and delivery

Manual work. A user starts a session, sends a chat message, or chooses Run now. Create a request identity, validate authority, then submit through the owning execution path.

Scheduled work. The existing scheduler claims a due occurrence and submits its task snapshot. Preserve finite schedules, occurrence budgets, retry lineage, pause behavior, and existing outcome checks.

Event-driven work. A connector saves an event. Match its account and conversation against enabled triggers. Apply deterministic filters before any optional model classifier.

A trigger can ignore the event, record it as context, update permitted memory, start work, or request owner review. The rule defines the permitted actions.

Use explicit modes: mentions only, topic watch, or every eligible incoming message. A topic classifier receives only permitted local context and has no action credentials.

For interactive messages, continue the chat's session. For a background automation, use a separate execution session and deliver its result back to the originating chat.

Serialize submissions within one session. Different sessions can run concurrently under resource limits. Briefly batch group bursts while keeping direct commands responsive.

Use source event plus trigger/version as the logical execution identity. Give an explicit manual replay its own audited attempt. Do not repeat an action simply because its trigger changed later.

Persist the input snapshot and context references used for a run. Capture its source, sender, trigger, task revision, permission scope, session, and result destinations.

E

Pub/sub intake and outgoing push

There are two separate flows inside the LFG service: inbound notifications start processing; outbound notifications inform people.

Direction Mechanism LFG responsibility
Inbound Gmail Mailbox watch through Google Pub/Sub Fetch changes since that account's saved cursor
Inbound Outlook Microsoft Graph subscriptions and webhooks Validate delivery and fetch required message data
Inbound other mail IMAP IDLE where supported Maintain mailbox connection and reconcile after reconnect
Inbound WhatsApp Baileys persistent connection and message events Normalize account/chat/sender identity and handle reconnects
Outbound app updates Authorized event stream with replay Keep screens consistent after reconnect
Outbound phone alerts APNs through LFG's existing push path Notify about results, failures, or required input
Outbound chat/email Provider send APIs Deliver replies or approved drafts to explicit destinations

Gmail publishes an account address and history cursor, not the full email. Fetch all relevant changes and create message-level events. Maintain one watch/cursor per connected mailbox, rather than one watch per thread.

A persistent Pub/Sub subscriber can run on the LFG host. Add public webhook ingress only when the selected provider requires it or a cloud relay improves availability.

Gmail watches need renewal. Delivery can lag or fail, so retain reconciliation timers. Normal agent work starts on events; maintenance timers repair subscriptions and gaps.

Source: Gmail push documentation.

Graph supports mailbox change subscriptions and HTTPS webhooks. Queue admitted notifications before lengthy processing, and renew subscriptions through the connector lifecycle.

Sources: Outlook notifications, webhook delivery.

IMAP IDLE watches a selected mailbox over an open connection. Baileys exposes connection and message events for the paired WhatsApp account. The latter remains unofficial integration with account and protocol risks.

Sources: IMAP IDLE, Baileys.

One WhatsApp account connection can route many groups and contacts. For each message, preserve both the conversation and its actual sender. For email, use the connection plus provider thread ID; never group solely by subject.

Persist delivery intentions separately from run completion. A completed agent answer does not prove WhatsApp delivery or an email send. Track app alert delivery separately too.

A phone notification points to a run, chat, or approval. The app fetches authoritative state when opened. Notification receipt must not be a prerequisite for server execution.

Approval buttons submit an authenticated command bound to the exact action and its expiry. Notification text or a group participant's reply cannot grant owner authority.

F

Memory, execution, and permissions

Memory. Keep curated memories in Markdown as agreed. Use separate folders for owner-private, group/contact, and explicitly shared project context.

Each chat has recent messages, a compact working summary, and retrieval from authorized notes and history. Keep original source references so summaries do not become the only evidence.

Serialize writes per memory scope and use atomic replacement. Record source and date, supersede changed facts, and support Remember, Edit, and Forget. A search index remains rebuildable from permitted source content.

Resolve scopes before retrieval. Opening a group chat in the owner's private app preserves that chat's group scope. Starting a separate private discussion can grant broader context explicitly.

Operational persistence. Keep existing session and task stores during the first phase. Add a durable inbox, processing claims, subscription checkpoints, and delivery outbox behind a separate operational-store interface.

Recommend SQLite for the new operational queue and deduplication ledger, where atomic claims and related updates matter. This does not move curated memory into a database. This storage choice remains a draft decision.

Do not mirror provider transcripts into a competing writable store. LFG owns message admission and execution metadata; provider adapters retain their canonical transcript ownership.

Execution. Keep agent reasoning independent of desktop allocation. API, CLI, and MCP tasks need no Space. Acquire a compatible desktop only when the work needs a screen.

Use existing host runners and Cua adapters. Respect session ownership: an externally owned session remains read-only unless the supported continuation or fork path grants control.

Assign one controller per desktop. Human takeover pauses the agent and retains the lease until the user finishes. Enforce the existing design's host memory reserve during desktop admission.

Permissions. Grant capabilities per principal, chat, connection, and task. Pass delegated agents only the context and tools their work requires.

Enforce approval at the action boundary. A worker with unrestricted shell and account cookies can bypass a nominal tool broker; constrain its credentials and tools accordingly.

Approve a reply policy when binding each channel. It can permit ordinary assistant replies in that chat.

For email drafts and account actions, follow the current design's inline owner approval. Any automatic-send policy must be explicit and bounded.

The Cua prototype documents automatic in-Space tool approval. UI approval cards alone cannot enforce this plan; execution adapters need actual action restrictions.

G

Deployment and recovery

Start with one authoritative LFG host for assistant orchestration. Use existing additional hosts as execution workers. Do not require centralized hosting for ordinary existing sessions.

Assign each chat, connection, and task an owner host. Route commands to that owner. Keep imported/native sessions discoverable through current fleet behavior.

A selected host can own multiple mailboxes and the assistant WhatsApp account. Do not connect the same stored WhatsApp credentials from two competing connector processes.

Keep identity, routing, state, and policy within the LFG service. Run connection adapters under its existing lifecycle or as supervised children. Reuse existing maintenance and recovery mechanisms.

Optional cloud ingress validates webhooks and queues notifications while the owner host is offline. It does not provide desktop execution or a WhatsApp connection unless those components actually run there.

Persist before acknowledging provider delivery. Deduplicate transport notifications and source messages separately. Advance cursors after discovered work reaches durable state.

Recover queued work after restart. Classify first-time mailbox history as context import unless the owner explicitly enables historical processing.

Use bounded retry, backoff, and an inspectable failed-event queue. Stop and surface uncertain external mutations rather than blindly replaying them.

Automatic host failover requires an explicit lease and credential handoff. Defer it initially. A disconnected host must show queued/unavailable status instead of pretending work has started.

Apply backpressure and limits per account, chat, trigger, and host. A busy group must not exhaust all execution capacity or classifier spend.

Show source-event receipt, filter decision, run state, permission waits, and delivery result as distinct evidence. Reuse the shared session-state resolver rather than inventing another busy heuristic.

Suggested run states: queued, starting, running, waiting for input/resource, succeeded, incomplete, failed, and cancelled. Waiting does not mean success.

H

Build sequence, acceptance, and evidence

Phase Deliverable Acceptance gate
1. Shared contracts Ownership, identity, work admission, origin metadata, run references Existing sessions and finite scheduled tasks behave unchanged
2. Lasting chats Stable chat IDs independent of Space allocation; Markdown memory Restart and session replacement preserve chat identity and memory scope
3. WhatsApp interface Existing bot account, selected groups, shared submission path Two groups remain isolated; app and WhatsApp share each group's chat
4. Event-triggered tasks Durable inbox, filters, classifiers, trigger definitions Repeated events launch one logical run; ignored events are inspectable
5. Email connections First Gmail mailbox, then a second; Outlook/IMAP as needed Independent cursors and thread routing; reconnects and expiry recover
6. Delivery and push Replies, drafts, app events, APNs, approval links Results reach the right destination; app state survives a missed alert
7. Delegated desktop work Resource leases, constrained actions, Cua execution Concurrent agents cannot share cursor control or bypass approval

Reuse existing push in phase 1 where possible. Phase 6 extends it to chat and event-run results; it is not a new APNs stack.

Use a complete vertical slice early: mention the bot in a group, run one permitted MCP action, view progress in LFG, and return a result.

Then add an email-triggered draft, a scheduled group summary, and a desktop task. Verify all three use the common execution and delivery contracts.

Test duplicate delivery, crashes between steps, overlapping rules, out-of-order events, bot reply loops, stale approvals, missing host capacity, and cross-group memory attempts.

Observed existing code. Sessions expose direct/closed conversation state and ownership. Scheduled tasks have time schedules and run records. The host exposes event replay and APNs device registration. Push code watches session transitions independently of app connections.

Design/prototype work. The newer chat design separates lasting threads from a shared Space pool. The older Cua Message prototype still binds messages and agent references to a Space. Treat the separation as work to implement.

Proposed additions. Channel bindings, account connectors, event intake, event triggers, generalized run references, scoped memory operations, delivery outbox, and enforced action permissions.

The current task model requires schedules. Its run trigger supports only scheduled and manual starts. The plan does not claim event triggers already exist.

Local source inspection:

  • Session and task models: src/sessions.ts, src/scheduled-tasks.ts, src/scheduled-task-api.ts.
  • API and push paths: src/commands/serve.ts, src/push/watcher.ts, src/push/apns.ts.
  • Chat design: .codex/design/cua-agent-threads/revision-brief.md and cua-agent-model.md.
  • Cua prototype: .worktrees/cua-message/src/cua-message.ts and docs/cua-message.md.

This is an architecture draft, not an implementation or deployment. No product files, databases, account connections, schedules, or running services changed.