Skip to content

LifeOSAI Agent Systems

Architecture & Code

The system below the UI

The agent system, company orchestration, the channels system, and the harness & agent runtime — how requests move, how agents are woken and executed, and where config, secrets, files, and live events are owned.

This document describes the LifeOSAI system architecture below the UI layer. It focuses on four areas:

  1. LifeOSAI agent system
  2. Company orchestration system
  3. Channels system
  4. Harness and agent runtime

It is meant to explain how requests move through the system, how agents are woken and executed, how channel messages are routed, and where runtime configuration, secrets, files, and live events are owned.

System Boundary

LifeOSAI is a cross-platform agent operating system. The same product model runs in two deployment modes:

  • Cloud mode: browser traffic is served by cloud services, and agent runtimes run in cloud infrastructure.
  • Local mode: the Tauri desktop app starts local sidecars and uses local files and local data stores.

The high-level service boundary is:

User / channel / operator
apps/web or external channel transport
apps/user-management
apps/api
packages/agent runtime adapter
Claude Code agent or Pi agent

apps/user-management is the browser-facing routing hub. It validates the user session and forwards product requests to the correct backend service. Agent execution is owned by apps/api, especially the orchestration engine and runtime invoker.

Service Responsibilities

LayerOwnerResponsibility
Product entryapps/webLifeOSAI chat, companies, apps, files, settings, and static-export compatible shell
Desktop shellapps/tauriLocal desktop wrapper, updater, sidecar process management
Routing hubapps/user-managementUser-authenticated API gateway, session reader, orchestration proxy, file proxy
Agent APIapps/apiAgent runtime APIs, company orchestration, wakeups, schedulers, channels, secrets
Runtime SDKpackages/agentRuntime abstraction, Claude Code adapter, Pi Agent adapter, normalized streaming events
Shared contractspackages/sharedOrchestration types, live event constants, env normalization, validators
Persistent dataPrisma DBCompanies, agents, issues, runs, routines, activity, secrets, channel state
Workspace dataFilesystem or mounted volumeChat workspaces, company project files, artifacts, skills, logs

LifeOSAI Agent System

The agent system covers normal chat, direct company-agent chat, and live run transcripts. It is intentionally separate from company task orchestration, although both paths can use the same runtime adapters.

Agent Interaction Modes

ModeDescriptionPrimary state
LifeOSAI chatUser chats with the selected runtime outside a company taskChat session id, runtime, model
Direct company-agent chatUser talks directly to a company agentCompany id, agent id, remembered session id
Live run transcriptUI follows an active orchestration runRun id, session id, runtime log stream
Completed transcript replayUI reads a previous run/sessionStored session messages
Channel conversationWhatsApp, Telegram, or another transport talks to an agentChannel session key, channel metadata, runtime session id

The frontend may present these modes differently, but the backend contract is the same idea: a session is attached to a runtime, the runtime streams events, and those events become transcript records or live run events.

Agent Capabilities

LifeOSAI agents can be extended by:

  • Skills: bundled, company-scoped, or user-uploaded capability folders.
  • Plugins: installed runtime extensions and tool bundles.
  • Connectors: external account or service integrations.
  • MCP servers: tool servers such as channels, browser, Slack, or custom tools.
  • Files: allowed workspace roots and company/project file roots.
  • Channels: transport-specific inbound messages and outbound replies.

The runtime process receives these capabilities through a combination of:

  • Runtime options passed by apps/api.
  • Environment variables assembled before invocation.
  • MCP server definitions.
  • Additional skill directories.
  • Adapter-specific command or SDK options.

Chat Session Flow

User sends message
apps/web
apps/user-management session/chat route
apps/api or runtime handler
packages/agent runtime
Claude Code or Pi Agent
normalized stream events
persisted transcript and/or live response

Session discovery and session message lookup are separate concerns. Listing sessions should stay limited to the known LifeOSAI root. Message lookup can resolve known company-agent transcript paths when a run/session already points there.

Company Orchestration System

The company system is the multi-agent orchestration layer. It owns companies, agents, projects, goals, issues, routines, activity, runs, approvals, and company-scoped files.

Core Domain Objects

ObjectPurpose
CompanyTenant boundary for agents, issues, projects, secrets, channels, and files
AgentCompany teammate with role, adapter config, runtime config, instructions, skills, and env
ProjectWorkspace and project-scoped configuration for issues and files
GoalHigh-level objective that can group issues and routines
IssueUnit of company work assigned to an agent or moved through lifecycle states
RoutineScheduled or trigger-based recurring work owned by an agent
Wakeup requestDurable queue item that tells an agent why it should run
Heartbeat runExecution record for one agent invocation
Activity logAudit/event history for user, agent, and system actions
Company secretCompany-scoped secret reference used by env bindings

Wake Sources

An agent run can be started from several sources:

  • Issue assigned to an agent.
  • Issue comment or mention.
  • Approval stage or review decision.
  • User clicks run heartbeat.
  • Background heartbeat timer fires.
  • Routine timer fires.
  • Channel inbound message is routed to the agent.
  • Direct company-agent chat message is sent.

All of these are normalized into wake context before execution. The agent should not need to know whether the wake came from the UI, a timer, an issue, or a channel except through the wake fields it receives.

Wakeup Queue Flow

apps/api/src/orchestration/engine/wakeup.ts owns the durable queue helpers.

Work source
enqueueWakeup(agentId, source, reason, payload, contextSnapshot)
agentWakeupRequest status queued
scheduler or immediate runner claims wakeup
heartbeat_runs row is created or updated
agent-invoker starts runtime process
wakeup completed or failed

The wakeup record captures:

  • agentId
  • source
  • triggerDetail
  • reason
  • payload
  • contextSnapshot
  • queue status and timestamps

The context snapshot is important because it is the stable handoff from product events to runtime execution. For example, an issue assignment wakeup includes the issue id and source context even if the issue later changes.

Run Lifecycle

Run status is not the same as agent status.

queued -> running -> succeeded | failed | cancelled

Run status describes one execution attempt. Agent status describes the visible state of the agent. A queued run should not overwrite an already-running agent as if the agent itself stopped running. The UI and event consumers should treat run lifecycle events and agent lifecycle events as separate streams.

Agent Status

Agent status should be updated only when the agent state actually changes, for example:

  • idle
  • active
  • running
  • paused
  • error

Queued work is a run property. It may be displayed near the agent, but it should not be treated as the agent’s primary lifecycle unless the backend deliberately sets an agent status event.

Live Event Bus

apps/api/src/orchestration/engine/event-bus.ts publishes company live events. The shared types live in packages/shared/src/orchestration/types/live.ts, and event names live in packages/shared/src/orchestration/constants.ts.

Important event families:

Event familyPurpose
heartbeat.run.queuedA run exists and is waiting or starting
heartbeat.run.runningA run has started
heartbeat.run.logRuntime SDK stream event, tool event, text, thinking, or system event
heartbeat.run.completedRun completed successfully
heartbeat.run.failedRun failed
heartbeat.run.cancelledRun was cancelled
agent.statusAgent state changed
issue.createdAgent or user created an issue
issue.updatedIssue fields changed, including status or assignee
issue.comment.createdComment was written
issue.deletedIssue was soft or hard deleted
activity.loggedAudit log entry was created

Live event payloads should include enough denormalized data for subscribers to update without refetching the entire company:

  • run id, run status, session id, adapter type, timestamps
  • agent id, agent name, role, status, adapter/runtime metadata
  • issue id, identifier, title, status, assignee, project, goal
  • activity actor, action, entity, details

Refetching is still acceptable for recovery, but the normal path should consume the event payload directly.

Activity Log

Activity logs are audit records, not only UI feed items. They preserve:

  • company id
  • actor type
  • actor id
  • agent id
  • run id
  • action
  • entity type
  • entity id
  • details

They are used to reconstruct what happened around an issue, run, routine, or agent action even after live events are gone from memory.

Channels System

Channels allow external transports to talk to LifeOSAI agents.

Current channel shape:

  • WhatsApp plugin
  • Telegram plugin
  • channel registry
  • channel session store
  • inbound dispatch
  • outbound message tool

The central outbound contract is the channel message tool. Claude Code receives it as mcp__channels__message. Pi Agent has an equivalent tool implementation under the runtime tools path.

Inbound Channel Flow

WhatsApp / Telegram inbound message
transport plugin
channel registry resolves company, agent, and session
channel dispatch builds system prompt and runtime options
runtime streams answer
stream sink sends reply through the transport
channel session metadata is persisted

The channel dispatcher is transport-agnostic. WhatsApp and Telegram provide their own stream sinks because their delivery behavior differs:

  • Telegram can update streamed messages more naturally.
  • WhatsApp usually buffers and sends a final message.

Channel To Company Orchestration

A channel message can either:

  • continue a direct channel conversation with an agent, or
  • create a wakeup for company work when the message maps to a company agent.

The wake context should carry channel metadata when source is channel:

  • channel chat id
  • sender phone or sender id
  • sender display name
  • inbound message text
  • channel alias

The runtime receives this as LIFEOSAI_* env so the agent can reason about the source without needing direct transport credentials.

Outbound Channel Tool

The outbound tool is intentionally shared across runtimes:

Agent runtime
mcp__channels__message or Pi channels tool
apps/api/src/channels/message-tool.ts
channel action runner
transport plugin
external chat

This keeps channel sending out of the model prompt and inside an audited tool path.

Harness And Agent Runtime

The harness is the runtime boundary between LifeOSAI orchestration and the actual agent engine.

Runtime Interface

packages/agent/src/runtimes/types.ts defines the runtime contract:

AgentRuntime
sessionId
stream(prompt)
sendMessage(content)
interrupt()
respondToPermission(toolUseId, response)
close()

Runtime options include:

  • cwd
  • systemPrompt
  • model
  • sessionId
  • permissionMode
  • allowedTools
  • env
  • mcpServers
  • userManagementUrl
  • projectPath
  • channelsMessageHandler
  • additionalSkillPaths

The rest of the application should not need to know if the underlying runtime is Claude Code or Pi Agent. It should consume normalized stream events.

Supported Runtimes

RuntimeLocationResponsibility
Claude Codepackages/agent/src/runtimes/claude-code-runtime.tsWrap Claude Code SDK sessions and stream SDK messages
Pi Agentpackages/agent/src/runtimes/pi-agent-runtime.tsRun Pi coding agent sessions and normalize events
Runtime factorypackages/agent/src/runtimes/factory.tsChoose the runtime by configured adapter/runtime key
Event normalizerpackages/agent/src/runtimes/event-normalizer.tsNormalize events for frontend and orchestration consumers

Agent Invoker

apps/api/src/orchestration/engine/agent-invoker.ts is the bridge from a heartbeat run to a runtime process.

It is responsible for:

  • resolving adapter type and model
  • resolving instructions files and skill paths
  • resolving the company, agent, and project cwd
  • loading agent env and project env
  • resolving company secret refs
  • merging runtime env
  • minting the run-scoped bearer token
  • injecting LIFEOSAI_* wake context
  • attaching the channels MCP server
  • starting Claude Code or Pi Agent
  • redacting secrets from logs
  • publishing run log events
  • returning session id, usage, result, and error state

Adapter Config Versus Runtime Config

Do not collapse these into one blob. They have different readers and different validation paths.

Field typeGoes inReason
env, cwd, command, args, modeladapter_configProcess-spawn and adapter inputs
instructionsBundleMode, instructionsRootPath, instructionsEntryFileadapter_configAdapter discovery logic
adapter-specific knobsadapter_configUsed by adapter execution
heartbeat enabled, intervalSec, wakeOnDemand, maxConcurrentRunsruntime_configScheduler policy
session compaction policyruntime_configSession rotation policy

Defaults should be applied at agent creation time. PATCH should merge only what the caller sends, so partial updates do not resurrect old defaults.

Runtime Env

LifeOSAI supports two env layers:

  1. Agent-scoped env: stored on the agent.
  2. Project-scoped env: stored on the project.

Project env overrides agent env on key collisions. This lets an operator define common runtime keys once at the agent level, then override them for one project.

Env values use the shared binding schema in packages/shared/src/orchestration/env-config.ts:

KEY=value
KEY={ type: "plain", value: "value" }
KEY={ type: "secret_ref", ref: "company-secret-name" }

Validation rules:

  • key must match ^[A-Za-z_][A-Za-z0-9_]*$
  • plaintext sensitive keys can be rejected in strict mode
  • ***REDACTED*** cannot be written back as a value
  • secret refs must belong to the same company
  • secret-backed keys are marked for log redaction

Run-Scoped API Authentication

Agent-exposed APIs are protected by a run-scoped bearer token:

Authorization: Bearer $LIFEOSAI_RUN_TOKEN

The token binds the request to:

  • company id
  • agent id
  • run id

This is stronger than trusting user-provided headers such as X-LIFEOSAI-AGENT-ID. Headers can still be useful for diagnostics or backward compatibility, but they should not be the security boundary.

Runtime Environment Variables

The invoker injects wake and execution context as environment variables. Common values include:

  • LIFEOSAI_API_URL
  • LIFEOSAI_RUN_TOKEN
  • LIFEOSAI_RUN_ID
  • LIFEOSAI_AGENT_ID
  • LIFEOSAI_COMPANY_ID
  • LIFEOSAI_WAKE_REASON
  • LIFEOSAI_WAKE_SOURCE
  • LIFEOSAI_TASK_ID or issue id when applicable
  • LIFEOSAI_TIMEZONE
  • channel-specific values when the wake source is a channel

Timer wakes do not always include an issue id. In that case the agent should follow its heartbeat or inbox instructions and inspect available work.

Operational Sequences

Issue Assignment

User or agent creates/updates issue with assignee
issue service persists issue
activity.logged is emitted
queueIssueAssignmentWakeup enqueues wakeup
scheduler claims wakeup
heartbeat run is queued
heartbeat.run.queued event
agent-invoker starts runtime
heartbeat.run.running event
runtime reads task/inbox via run-token APIs
runtime comments, updates issue, writes files, or asks for approval
issue/activity/run live events stream to subscribers
heartbeat.run.completed or heartbeat.run.failed

Direct Company-Agent Chat

User selects company agent
direct chat session is resolved or created
selected runtime/model comes from agent configuration
message is sent through runtime adapter
response streams back to the chat panel
session id is remembered for that agent

Direct chat does not have to create a company issue. It can still use company context, agent instructions, skills, files, env, and channel tools.

Heartbeat Timer

Heartbeat scheduler tick
reads agents with runtime_config.heartbeat.enabled
checks interval and active run policy
enqueueWakeup(source=“timer”, reason=“heartbeat_timer”)
run starts with no issue id
agent inspects inbox-lite or heartbeat instructions
agent exits if no work is needed

Turning heartbeat on in the agent configuration updates scheduler input. The next scheduler tick should observe the new runtime config without requiring the agent process to stay alive.

Routine Timer

Routine scheduler tick
finds active routine triggers by nextFireAt
creates routine wake context
starts or queues agent run according to routine policy
updates nextFireAt in UTC
displays next run in the user’s/browser timezone

UTC is the storage format. The routine timezone controls when the schedule fires. Browser timezone can be used as a default when the user or agent did not specify a timezone.

Channel Inbound Message

External channel message
transport plugin verifies and parses message
channel session maps to company/agent/session
dispatch builds runtime context
runtime answers
stream sink sends or edits outbound response
channel session and audit state update

Local And Cloud Deployment

Local Mode

Local mode is built around the Tauri app and sidecar services:

PortService
3000apps/web
3001apps/user-management
3002apps/auth
4000apps/api

Important local roots:

  • ~/LIFEOSAI
  • ~/.lifeosai/companies
  • local database, usually SQLite or local Postgres depending on mode

Cloud Mode

Cloud mode uses GCP and CI/CD:

  • GCP project: lifeosai-481608
  • region: asia-south-1
  • Artifact Registry repo: docker-images
  • Cloud Run services: web, auth, user-management
  • Compute Engine or runtime containers for agent execution
  • workspace root: /workspace/LIFEOSAI

The product API surface should remain the same between local and cloud. Only the execution locality, filesystem root, and infrastructure backing services change.

Security Boundaries

BoundaryEnforcement
User sessionapps/user-management validates browser/desktop requests
Company accessOrchestration services assert company access before reads/writes
Agent run APIsRun-scoped bearer token validates company, agent, and run
SecretsCompany-scoped secret refs validated on write and resolved at invocation
FilesSession and file readers allow only known LifeOSAI roots
LogsSecret-backed env values are redacted before persistence
ChannelsTransport plugins and channel sessions map inbound messages to known company/agent context

Code Map

AreaMain files
Runtime interfacepackages/agent/src/runtimes/types.ts
Claude Code runtimepackages/agent/src/runtimes/claude-code-runtime.ts
Pi Agent runtimepackages/agent/src/runtimes/pi-agent-runtime.ts
Runtime event normalizationpackages/agent/src/runtimes/event-normalizer.ts
Agent invokerapps/api/src/orchestration/engine/agent-invoker.ts
Wakeup queueapps/api/src/orchestration/engine/wakeup.ts
Heartbeat schedulerapps/api/src/orchestration/engine/heartbeat.ts
Routine schedulerapps/api/src/orchestration/engine/routine-scheduler.ts
Event busapps/api/src/orchestration/engine/event-bus.ts
Run authapps/api/src/orchestration/auth/run-token.ts
Agent API guardapps/api/src/orchestration/routes/middleware.ts
Issuesapps/api/src/orchestration/services/issues.ts
Agentsapps/api/src/orchestration/services/agents.ts
Projectsapps/api/src/orchestration/services/projects.ts
Routinesapps/api/src/orchestration/services/routines.ts
Activityapps/api/src/orchestration/services/activity-log.ts
Secretsapps/api/src/orchestration/services/secrets.ts
Env configpackages/shared/src/orchestration/env-config.ts
Live event typespackages/shared/src/orchestration/types/live.ts
Channels dispatchapps/api/src/channels/dispatch.ts
Channels message toolapps/api/src/channels/message-tool.ts
WhatsApp channelapps/api/src/channels/plugins/whatsapp.ts
Telegram channelapps/api/src/channels/plugins/telegram.ts
Session readerapps/user-management/src/sessions/reader.ts