LifeOSAI Agent Systems
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:
- LifeOSAI agent system
- Company orchestration system
- Channels system
- 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:
apps/web or external channel transportapps/user-managementapps/apipackages/agent runtime adapterapps/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
| Layer | Owner | Responsibility |
|---|---|---|
| Product entry | apps/web | LifeOSAI chat, companies, apps, files, settings, and static-export compatible shell |
| Desktop shell | apps/tauri | Local desktop wrapper, updater, sidecar process management |
| Routing hub | apps/user-management | User-authenticated API gateway, session reader, orchestration proxy, file proxy |
| Agent API | apps/api | Agent runtime APIs, company orchestration, wakeups, schedulers, channels, secrets |
| Runtime SDK | packages/agent | Runtime abstraction, Claude Code adapter, Pi Agent adapter, normalized streaming events |
| Shared contracts | packages/shared | Orchestration types, live event constants, env normalization, validators |
| Persistent data | Prisma DB | Companies, agents, issues, runs, routines, activity, secrets, channel state |
| Workspace data | Filesystem or mounted volume | Chat 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
| Mode | Description | Primary state |
|---|---|---|
| LifeOSAI chat | User chats with the selected runtime outside a company task | Chat session id, runtime, model |
| Direct company-agent chat | User talks directly to a company agent | Company id, agent id, remembered session id |
| Live run transcript | UI follows an active orchestration run | Run id, session id, runtime log stream |
| Completed transcript replay | UI reads a previous run/session | Stored session messages |
| Channel conversation | WhatsApp, Telegram, or another transport talks to an agent | Channel 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
apps/webapps/user-management session/chat routeapps/api or runtime handlerpackages/agent runtimeSession 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
| Object | Purpose |
|---|---|
| Company | Tenant boundary for agents, issues, projects, secrets, channels, and files |
| Agent | Company teammate with role, adapter config, runtime config, instructions, skills, and env |
| Project | Workspace and project-scoped configuration for issues and files |
| Goal | High-level objective that can group issues and routines |
| Issue | Unit of company work assigned to an agent or moved through lifecycle states |
| Routine | Scheduled or trigger-based recurring work owned by an agent |
| Wakeup request | Durable queue item that tells an agent why it should run |
| Heartbeat run | Execution record for one agent invocation |
| Activity log | Audit/event history for user, agent, and system actions |
| Company secret | Company-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.
enqueueWakeup(agentId, source, reason, payload, contextSnapshot)agentWakeupRequest status queuedheartbeat_runs row is created or updatedagent-invoker starts runtime processThe wakeup record captures:
agentIdsourcetriggerDetailreasonpayloadcontextSnapshot- 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 | cancelledRun 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 family | Purpose |
|---|---|
heartbeat.run.queued | A run exists and is waiting or starting |
heartbeat.run.running | A run has started |
heartbeat.run.log | Runtime SDK stream event, tool event, text, thinking, or system event |
heartbeat.run.completed | Run completed successfully |
heartbeat.run.failed | Run failed |
heartbeat.run.cancelled | Run was cancelled |
agent.status | Agent state changed |
issue.created | Agent or user created an issue |
issue.updated | Issue fields changed, including status or assignee |
issue.comment.created | Comment was written |
issue.deleted | Issue was soft or hard deleted |
activity.logged | Audit 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
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:
mcp__channels__message or Pi channels toolapps/api/src/channels/message-tool.tsThis 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:
cwdsystemPromptmodelsessionIdpermissionModeallowedToolsenvmcpServersuserManagementUrlprojectPathchannelsMessageHandleradditionalSkillPaths
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
| Runtime | Location | Responsibility |
|---|---|---|
| Claude Code | packages/agent/src/runtimes/claude-code-runtime.ts | Wrap Claude Code SDK sessions and stream SDK messages |
| Pi Agent | packages/agent/src/runtimes/pi-agent-runtime.ts | Run Pi coding agent sessions and normalize events |
| Runtime factory | packages/agent/src/runtimes/factory.ts | Choose the runtime by configured adapter/runtime key |
| Event normalizer | packages/agent/src/runtimes/event-normalizer.ts | Normalize 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 type | Goes in | Reason |
|---|---|---|
| env, cwd, command, args, model | adapter_config | Process-spawn and adapter inputs |
| instructionsBundleMode, instructionsRootPath, instructionsEntryFile | adapter_config | Adapter discovery logic |
| adapter-specific knobs | adapter_config | Used by adapter execution |
| heartbeat enabled, intervalSec, wakeOnDemand, maxConcurrentRuns | runtime_config | Scheduler policy |
| session compaction policy | runtime_config | Session 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:
- Agent-scoped env: stored on the agent.
- 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=valueKEY={ 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_TOKENThe 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_URLLIFEOSAI_RUN_TOKENLIFEOSAI_RUN_IDLIFEOSAI_AGENT_IDLIFEOSAI_COMPANY_IDLIFEOSAI_WAKE_REASONLIFEOSAI_WAKE_SOURCELIFEOSAI_TASK_IDor issue id when applicableLIFEOSAI_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
activity.logged is emittedqueueIssueAssignmentWakeup enqueues wakeupheartbeat.run.queued eventagent-invoker starts runtimeheartbeat.run.running eventheartbeat.run.completed or heartbeat.run.failedDirect Company-Agent Chat
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
runtime_config.heartbeat.enabledenqueueWakeup(source=“timer”, reason=“heartbeat_timer”)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
nextFireAtnextFireAt in UTCUTC 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
Local And Cloud Deployment
Local Mode
Local mode is built around the Tauri app and sidecar services:
| Port | Service |
|---|---|
| 3000 | apps/web |
| 3001 | apps/user-management |
| 3002 | apps/auth |
| 4000 | apps/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
| Boundary | Enforcement |
|---|---|
| User session | apps/user-management validates browser/desktop requests |
| Company access | Orchestration services assert company access before reads/writes |
| Agent run APIs | Run-scoped bearer token validates company, agent, and run |
| Secrets | Company-scoped secret refs validated on write and resolved at invocation |
| Files | Session and file readers allow only known LifeOSAI roots |
| Logs | Secret-backed env values are redacted before persistence |
| Channels | Transport plugins and channel sessions map inbound messages to known company/agent context |
Code Map
| Area | Main files |
|---|---|
| Runtime interface | packages/agent/src/runtimes/types.ts |
| Claude Code runtime | packages/agent/src/runtimes/claude-code-runtime.ts |
| Pi Agent runtime | packages/agent/src/runtimes/pi-agent-runtime.ts |
| Runtime event normalization | packages/agent/src/runtimes/event-normalizer.ts |
| Agent invoker | apps/api/src/orchestration/engine/agent-invoker.ts |
| Wakeup queue | apps/api/src/orchestration/engine/wakeup.ts |
| Heartbeat scheduler | apps/api/src/orchestration/engine/heartbeat.ts |
| Routine scheduler | apps/api/src/orchestration/engine/routine-scheduler.ts |
| Event bus | apps/api/src/orchestration/engine/event-bus.ts |
| Run auth | apps/api/src/orchestration/auth/run-token.ts |
| Agent API guard | apps/api/src/orchestration/routes/middleware.ts |
| Issues | apps/api/src/orchestration/services/issues.ts |
| Agents | apps/api/src/orchestration/services/agents.ts |
| Projects | apps/api/src/orchestration/services/projects.ts |
| Routines | apps/api/src/orchestration/services/routines.ts |
| Activity | apps/api/src/orchestration/services/activity-log.ts |
| Secrets | apps/api/src/orchestration/services/secrets.ts |
| Env config | packages/shared/src/orchestration/env-config.ts |
| Live event types | packages/shared/src/orchestration/types/live.ts |
| Channels dispatch | apps/api/src/channels/dispatch.ts |
| Channels message tool | apps/api/src/channels/message-tool.ts |
| WhatsApp channel | apps/api/src/channels/plugins/whatsapp.ts |
| Telegram channel | apps/api/src/channels/plugins/telegram.ts |
| Session reader | apps/user-management/src/sessions/reader.ts |